Luke a Pro

Luke Sun

Developer & Marketer

🇺🇦
EN||

JWT (JSON Web Token) Attacks

| , 5 minutes reading.

1. Definition

JWT (JSON Web Token) is a compact, URL-safe token format used for authentication and information exchange. JWT attacks exploit weaknesses in how applications create, validate, or handle these tokens.

A JWT consists of three parts: header.payload.signature

Common JWT vulnerabilities allow attackers to:

  • Forge valid tokens without knowing the secret
  • Escalate privileges by modifying token claims
  • Bypass authentication entirely
  • Impersonate other users

2. Technical Explanation

JWT Structure:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.    <- Header (Base64)
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ.  <- Payload (Base64)
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c     <- Signature

Header: Specifies the algorithm (e.g., HS256, RS256, none) Payload: Contains claims (user ID, role, expiration) Signature: Verifies the token was not tampered with

Common JWT Attack Types:

  1. Algorithm Confusion (alg=none): Some libraries accept "alg": "none", allowing unsigned tokens.

  2. Algorithm Switching (RS256 to HS256): Tricking the server into using the public key as an HMAC secret.

  3. Weak Secret Brute Force: Cracking weak HMAC secrets offline.

  4. JWT Header Injection (jku/x5u): Pointing to attacker-controlled key servers.

  5. Claim Tampering: Modifying payload without proper signature validation.

3. Attack Flow (Algorithm Confusion)

sequenceDiagram
    participant Attacker
    participant Server as Web Server
    participant Library as JWT Library

    Note over Server: Server uses RS256<br/>Public/Private key pair

    Attacker->>Attacker: Obtain servers public key

    Attacker->>Attacker: Create forged JWT<br/>Header: alg=HS256<br/>Payload: admin=true

    Attacker->>Attacker: Sign with public key<br/>treating it as HMAC secret

    Attacker->>Server: Request with forged JWT

    Server->>Library: Verify JWT

    Library->>Library: Read alg=HS256 from header<br/>Use public key as HMAC secret<br/>Signature matches!

    Library-->>Server: Token valid

    Server-->>Attacker: Access granted as admin

4. Real-World Case Study: Auth0 Algorithm Confusion (2015)

Target: Auth0 JWT library users. Vulnerability Class: Algorithm Confusion (CVE-2015-9235).

The Vulnerability: Auth0’s jsonwebtoken library for Node.js had a critical flaw. When verifying tokens signed with RSA (RS256), if an attacker changed the algorithm to HS256 in the header, the library would use the RSA public key as the HMAC secret.

Why This Worked:

  1. RS256 uses asymmetric encryption: private key signs, public key verifies.
  2. HS256 uses symmetric encryption: same secret for both signing and verification.
  3. Public keys are often… public (in JWKS endpoints, certificates, etc.).
  4. The library trusted the alg header from the token itself.

The Attack:

// Original token (RS256)
// Header: {"alg": "RS256", "typ": "JWT"}
// Signed with server's private key

// Attacker's forged token (HS256)
// Header: {"alg": "HS256", "typ": "JWT"}
// Payload: {"user": "admin", "role": "superuser"}
// Signed with server's PUBLIC key as HMAC secret

Impact: Any application using the vulnerable library could have their authentication completely bypassed. This affected thousands of applications using Auth0’s library.

5. Detailed Defense Strategies

A. Explicit Algorithm Specification

Never trust the algorithm specified in the token header.

// Bad: Algorithm from token header
jwt.verify(token, secret);

// Good: Explicit algorithm whitelist
jwt.verify(token, secret, { algorithms: ['HS256'] });

// Good: For RSA
jwt.verify(token, publicKey, { algorithms: ['RS256'] });

B. Strong Secrets

For HMAC-based algorithms, use cryptographically strong secrets.

  • Minimum Length: 256 bits (32 bytes) for HS256.
  • Random Generation: Use cryptographic random generators.
  • No Dictionary Words: Avoid guessable passwords.
# Generate strong secret
openssl rand -base64 32

Weak secrets can be cracked offline:

# Attacker can brute force weak secrets
hashcat -m 16500 jwt.txt wordlist.txt

C. Proper Key Management

  • Separate Keys: Different keys for different environments.
  • Key Rotation: Regular rotation with overlap period.
  • Secure Storage: Use HSM or secrets management services.

D. Validate All Claims

Don’t just verify the signature—validate the payload.

jwt.verify(token, secret, {
  algorithms: ['HS256'],
  issuer: 'https://myapp.com',      // Validate issuer
  audience: 'https://api.myapp.com', // Validate audience
  clockTolerance: 30,                // Allow 30s clock skew
  maxAge: '1h'                       // Reject tokens older than 1 hour
});

E. Short Expiration Times

Minimize the window of opportunity for stolen tokens.

  • Access Tokens: 15 minutes or less.
  • Refresh Tokens: Hours to days, with secure storage.
  • Implement Token Revocation: Maintain a blocklist for compromised tokens.

F. Avoid Sensitive Data in Payload

JWTs are signed, not encrypted (unless using JWE).

// Bad: Sensitive data in JWT
{
  "user_id": 123,
  "credit_card": "4111-1111-1111-1111",  // Never do this!
  "ssn": "123-45-6789"                   // Never do this!
}

// Good: Only non-sensitive identifiers
{
  "user_id": 123,
  "role": "user",
  "exp": 1609459200
}

G. Use Asymmetric Algorithms for Distributed Systems

When multiple services need to verify tokens:

  • RS256/RS384/RS512: RSA signatures
  • ES256/ES384/ES512: ECDSA signatures

Only the auth server has the private key; all services can verify with the public key.

H. Implement JTI (JWT ID) for Replay Protection

{
  "jti": "unique-token-id-abc123",  // Unique identifier
  "user_id": 123,
  "exp": 1609459200
}

Track used jti values to prevent token replay.

6. References