JWT vulnerabilities

A JWT (JSON Web Token) is like an access pass that the server gives you after you log in. It’s a long string with three parts, separated by dots:

HEADER.PAYLOAD.SIGNATURE
eyJhbGciOi... (header).eyJzdWIiOi... (payload).SGVsbG8sIHdv... (signature)

What does each part contain?

  1. Header

    • Describes the algorithm used to sign the token (e.g., HS256, RS256).

    • It's a Base64-encoded JSON.

  2. Payload

    • Contains “claims” – data like your name, role, email, isAdmin status, etc.

    • Also a Base64-encoded JSON.

    • Anyone can read this part if they have the token!

  3. Signature

    • This ensures the token hasn’t been tampered with.

    • Created using a secret key known only to the server.

    • If you change the header or payload, the signature becomes invalid.

Risky Header Parameters

  1. alg: Can be changed to none to bypass signature validation.

  2. jwk: May allow the attacker to provide a public key and sign a token with their private key.

  3. kid: If not validated securely, can be exploited via path traversal or external key injection.

Useful resouse:

  • JWT Editor

Methodology

Signature Validation Bypass

  • Modify the payload (e.g., change user ID, role, etc.) to impersonate another user.

  • Observe if the server still accepts the token, indicating improper signature verification.

Algorithm none Bypass

  • Change the alg parameter in the header to none.

  • Remove the signature part but keep the final dot (e.g., header.payload.).

  • If accepted, the server is not validating the signature.

Brute Force the Signature Key

  • Developers may forget to change default secrets.

  • Use Hashcat to brute-force the key:

hashcat -a 0 -m 16500 'HEADER.PAYLOAD.SIGNATURE' jwt.secrets.list

Header Injection Techniques

🔓 jwk Header Injection

  • Generate an RSA key in Burp Suite.

  • Modify the payload as needed.

  • In Burp Repeater, use Attack → Embedded JWK.

  • Send the token with your public key embedded in the header.

🌐 jku Header Injection

  • Host a JWK Set file like:

{
  "keys": [ YOUR_JWK ]
}
  • In the JWT header:

    • Set kid to your key ID.

    • Add a jku parameter pointing to your hosted JWK Set.

  • Sign the token with your private key and send it.

🗂️ kid Path Traversal

  • Create a symmetric key in Burp.

  • Replace the k value with a Base64-encoded null byte (AA==).

  • In the header, set:

    "kid": "../../../../../../../dev/null"
  • Modify the payload as needed, sign and send.


Algorithm Confusion Attack (RS256 → HS256)

  1. Retrieve the server's public key (commonly found at /jwks.json or /.well-known/jwks.json).

  2. Generate a new RSA Key in Burp → Export as PEM.

  3. Convert PEM to Base64.

  4. Create a Symmetric Key and replace the k value with the Base64 version.

  5. In the header:

    "alg": "HS256"
  6. Modify the payload as needed, sign and send.


Algorithm Confusion Without Exposed Key

  1. Obtain two JWTs (either same user at different sessions, or different users).

  2. Use sig2n to derive the HMAC key:

sudo docker run --rm -it portswigger/sig2n TOKEN1 TOKEN2
  1. Copy the derived key.

  2. Create a new Symmetric Key in Burp and set k to that key.

  3. Set alg in the header to HS256.

  4. Modify the payload, sign, and send.

Last updated