intermediatecat/web~2 min read

JWT Attacks & Bypass

Crack weak signing secrets, exploit signature verification flaws, and abuse algorithm confusion in JSON Web Tokens.

// prerequisite reading

Anatomy of a JWT

A JSON Web Token consists of three base64url-encoded parts separated by dots (.):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwicm9sZSI6InVzZXIifQ.Signature...
[               HEADER              ].[               PAYLOAD              ].[   SIGNATURE   ]
  1. Header: Algorithm & token type (e.g., {"alg": "HS256", "typ": "JWT"}).
  2. Payload: Claims and user metadata (e.g., {"user": "admin", "role": "admin"}).
  3. Signature: Verification hash created using secret key / private key over Header.Payload.

1. Unverified Signature / none Algorithm

Some flawed JWT libraries accept tokens signed with the none algorithm, bypassing signature checks entirely:

  1. Decode the token header and payload.
  2. Modify payload claims (e.g., "role": "admin" or "user": "admin").
  3. Change header algorithm to "alg": "none" (or "None", "NONE", "nOnE").
  4. Remove the signature segment completely while retaining the trailing dot:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.

2. Brute-Forcing Weak Secrets (HS256)

Symmetric JWT signing (HS256) relies on a shared secret key. If the secret is weak, it can be cracked offline using dictionary attacks.

Using hashcat

hashcat -m 16500 jwt_token.txt /usr/share/wordlists/rockyou.txt

Using jwt_tool

python3 jwt_tool.py <JWT_STRING> -d /usr/share/wordlists/rockyou.txt

Once the secret is recovered (e.g., secret123), re-sign forged payloads using PyJWT or jwt_tool:

import jwt

forged_token = jwt.encode({"user": "admin", "role": "admin"}, "secret123", algorithm="HS256")
print(forged_token)

3. Algorithm Confusion Attack (RS256 to HS256)

RS256 uses asymmetric keys (Private key to sign, Public key to verify). HS256 uses a symmetric secret key.

If an application verifies signatures using RS256 but accepts HS256 tokens:

  1. Obtain the target server’s public key (e.g., from /jwks.json, /.well-known/jwks.json, or exported TLS cert).
  2. Change the header algorithm from RS256 to HS256.
  3. Sign the forged token using the public key string as the symmetric HMAC secret key!

4. Key ID (kid) Header Injection

The kid header parameter specifies which key file or database entry to use for verification.

  • Path Traversal in kid: Set kid to ../../../../dev/null or a known file on disk (like /etc/issue), then sign the token with an empty string or the contents of that file as the HMAC key:
    {
      "alg": "HS256",
      "typ": "JWT",
      "kid": "../../../../../dev/null"
    }
  • SQL Injection in kid: Inject SQL statements into kid parameter to return controlled keys:
    {
      "alg": "HS256",
      "kid": "' UNION SELECT 'my_known_secret' -- -"
    }
    Then sign payload with my_known_secret.