Login
ChallengesLearn
Scoreboard
Teams
SPNZ

LearnAccess ControlJWT Attacks
Access Control·Lesson 7 of 12

JWT Attacks

alg=none, RS256-to-HS256 confusion, kid injection, weak secret brute-force. The stateless token that lets an attacker forge any identity if the server misconfigures validation.

Intermediate14 min
Access ControlJWTAuth
Loading lesson…
PreviousAPI Access ControlNextCSRF

© 2026 SPNZ.

Terms of ServicePrivacy PolicyCookie Policy

JSON Web Tokens (JWTs) are stateless: the server issues a signed token and never stores it. Every subsequent request carries the token, and the server trusts the signature. If the server misconfigures JWT validation, an attacker can forge tokens — and with them, any identity.

What you'll be able to do
  • Explain how JWT stateless authentication works (header, payload, signature).
  • Identify the alg=none attack, RS256-to-HS256 key confusion, and kid injection.
  • Understand the 2015 alg=none and 2018 Auth0 CVE-2018-6874 incidents.
  • Apply strict JWT validation: algorithm whitelist, key pinning, and kid path sanitisation.
Key terms
JWT
JSON Web Token — a URL-safe token format consisting of a base64-encoded header, payload, and signature, separated by dots. The header specifies the signing algorithm; the payload contains claims; the signature verifies integrity (RFC 7519).
alg=none
A JWT algorithm value that tells the server to skip signature verification entirely. Many early JWT libraries accepted this by default (CWE-347).
Key confusion
An attack where a server that expects RS256 (asymmetric) is tricked into using the public key as an HMAC secret for HS256, allowing token forgery by anyone who has the public key.
What is it?

The token the server trusts

A JWT is three base64url-encoded segments joined by dots: header.payload.signature. The header declares the signing algorithm (typically HS256, RS256, or ES256), and the payload contains claims such as sub(subject), role, and exp. The signature is computed over the header and payload using the declared algorithm.

The vulnerability arises when the server trusts the algorithm declared in the JWT header without verifying it against an expected value. An attacker can change "alg": "RS256" to "alg": "none", set any payload claims they want, and omit the signature. If the server's JWT library accepts the none algorithm, the forged token is treated as valid.

JWT attack flow
Mini Map
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Try it

JWT Debugger

The sandbox below simulates a JWT debugger. Inspect the header, payload, and signature of a sample token. Toggle "strict validation" to see how the server accepts or rejects tampered tokens. Try switching the algorithm to none and observe the server's behaviour.

staging/debug/jwt
JWT Debugger
Click a preset above or paste your own token.
Header
{
  "alg": "RS256",
  "typ": "JWT"
}
Payload
{
  "sub": "1234567890",
  "name": "Alice Johnson",
  "role": "user",
  "iat": 1516239022
}
Signature
abc123def456signature789
Real-world relevance

The alg=none epidemic and Auth0 CVE-2018-6874

In 2015, security researcher Tim McLean published a survey of 19 popular JWT libraries across multiple languages. Eleven of them were vulnerable to the alg=none attack by default. The libraries would parse the header, see "alg": "none", and skip signature verification entirely. This meant any attacker who could modify a JWT in transit — or generate their own — could impersonate any user. The vulnerability was classified as CWE-347 (Improper Verification of Cryptographic Signature).

In 2018, a more subtle variant was discovered in the Auth0jsonwebtokenNode.js library (CVE-2018-6874). The server was configured to use RS256 (RSA signature, asymmetric). The attacker changed the algorithm to HS256 (HMAC, symmetric) and signed the token using the server's own public RSA key — which is publicly available. Since the JWT library used the provided algorithm to verify the signature, it treated the HMAC as valid. The fix was to whitelist accepted algorithms on the server and reject any token whose algorithm was not in the list.

Mitigation

Algorithm whitelist, key pinning, kid validation

Three defences, applied together, close the major JWT attack vectors.

javascriptvulnerable
// VULNERABLE — trusts the header's algorithm
jwt.verify(token, secret);  // attacker sets alg=none or alg=HS256

// SAFE — whitelist accepted algorithms
jwt.verify(token, RSA_PUBLIC_KEY, { algorithms: ['RS256'] });

// SAFE — validate kid (key ID) against an allowlist
const allowedKids = new Set(['key-2024-a', 'key-2024-b']);
const decoded = jwt.decode(token, { complete: true });
if (!allowedKids.has(decoded.header.kid)) {
  throw new Error('Unknown key ID');
}

// SAFE — reject alg=none explicitly
if (decoded.header.alg === 'none') {
  throw new Error('alg=none is not permitted');
}

Additional best practices: use short token expiration (15-30 minutes); implement token refresh rotation; store the signing key securely and rotate it periodically; never expose the private key to the frontend; and prefer asymmetric algorithms (RS256, ES256) so the public key can be distributed without compromising the signing key.

Further reading
  • CWE-347: Improper Verification of Cryptographic Signature(MITRE)
  • Critical vulnerabilities in JSON Web Token libraries (McLean, 2015)(Auth0)
  • JWT Handbook(Auth0)
Key takeaways

What to remember

  • JWTs are stateless — if the server trusts a forged token, there is no server-side session to revoke.
  • The alg=none attack works because many JWT libraries accept the algorithm from the header without validating it against an expected list.
  • RS256-to-HS256 key confusion: the attacker uses the server's public RSA key as an HMAC secret to forge tokens. The fix is an explicit algorithms whitelist.
  • The kid (key ID) header can be a path traversal vector if the server uses it to load a key file without validation.
  • Always whitelist accepted algorithms, pin the expected key, rejectalg=none, and validate kid against an allowlist.

Knowledge check

0/3 answered · 0 correct
  1. 1.What is the alg=none attack against JWT?

  2. 2.How does the RS256-to-HS256 key confusion attack work?

  3. 3.A server validates JWTs by calling jwt.verify(token, secret). What is the most likely vulnerability?