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.
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.
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.
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.
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.
{
"alg": "RS256",
"typ": "JWT"
}{
"sub": "1234567890",
"name": "Alice Johnson",
"role": "user",
"iat": 1516239022
}abc123def456signature789
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.
Three defences, applied together, close the major JWT attack vectors.
// 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.
alg=none attack works because many JWT libraries accept the algorithm from the header without validating it against an expected list.kid (key ID) header can be a path traversal vector if the server uses it to load a key file without validation.alg=none, and validate kid against an allowlist.1.What is the alg=none attack against JWT?
2.How does the RS256-to-HS256 key confusion attack work?
3.A server validates JWTs by calling jwt.verify(token, secret). What is the most likely vulnerability?