Introduction
Your application uses JWTs for authentication. Everything works until a security researcher discovers they can forge admin tokens by changing the algorithm to "none" in the header. Your verification library accepts these unsigned tokens as valid, granting administrative access to anyone who knows the trick.
JWTs provide a standardized format for transmitting claims between parties. While well-designed, implementation vulnerabilities are common and severe. This guide explores JWT vulnerabilities, secure implementation patterns, and why AI-powered testing identifies token security issues effectively.
Understanding the Risk
The "none" Algorithm Attack
The JWT specification includes "alg": "none" for unsecured tokens. Vulnerable libraries accept this:
// Attacker's modified header
{ "alg": "none", "typ": "JWT" }
// Vulnerable verification
jwt.verify(token, secret); // Accepts "none" algorithmAlgorithm Confusion (RS256 to HS256)
When applications use RS256, attackers may switch to HS256 and sign with the public key:
// Server expects RS256 (asymmetric)
// Attacker uses HS256 (symmetric) signed with public key
jwt.verify(token, publicKey); // Public key used as HMAC secretWeak Signing Secrets
Short secrets can be brute-forced:
hashcat -a 0 -m 16500 jwt_token.txt wordlist.txtSensitive Data in Payload
JWT payloads are encoded, not encrypted. Anyone with the token can decode and read claims.
Prevention Best Practices
Explicitly Specify Allowed Algorithms
jwt.verify(token, secret, {
algorithms: ['HS256'] // Only accept HS256
});Python:
jwt.decode(token, SECRET_KEY, algorithms=['HS256'])Use Strong Signing Secrets
import secrets
SECRET_KEY = secrets.token_hex(32) # 256 bitsValidate All Claims
jwt.verify(token, secret, {
algorithms: ['HS256'],
issuer: 'https://auth.example.com',
audience: 'https://api.example.com'
});Short-Lived Access Tokens with Refresh Tokens
const accessToken = jwt.sign(
{ sub: user.id, type: 'access' },
secret,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ sub: user.id, type: 'refresh', jti: generateUUID() },
refreshSecret,
{ expiresIn: '7d' }
);Secure Token Storage
// Refresh tokens: HttpOnly cookies
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
// Access tokens: memory only, use Authorization headerImplement Token Revocation
def revoke_token(jti, exp):
ttl = exp - int(time.time())
redis_client.setex(f"revoked:{jti}", ttl, "1")
def is_token_revoked(jti):
return redis_client.exists(f"revoked:{jti}")Keep Payloads Minimal
// GOOD
{ "sub": "user_id_123", "iat": 1234567890, "exp": 1234571490 }
// BAD - sensitive data exposure
{ "sub": "user_id_123", "email": "user@example.com", "ssn": "123-45-6789" }Why Traditional Pentesting Falls Short
JWT vulnerabilities require understanding token structure, library behaviors, and cryptographic concepts. Testing requires crafting malformed tokens with various algorithm manipulations and analyzing library-specific behaviors.
How AI-Powered Testing Solves It
RedVeil's AI agents analyze JWT implementations comprehensively, testing for algorithm confusion, weak secrets, and missing validation. The platform crafts attack tokens with various manipulations and verifies whether forged credentials are accepted.
Conclusion
JWTs introduce significant security risks when implemented incorrectly. The most critical vulnerabilities—algorithm confusion and weak secrets—can lead to complete authentication bypass.
Secure implementation requires explicit algorithm specification, strong signing secrets, proper claim validation, and secure token storage.
AI-powered penetration testing from RedVeil identifies JWT vulnerabilities in your authentication system.
Protect your authentication from JWT attacks—test with RedVeil today.