51. JWT Security Vulnerabilities: Common Mistakes and Exploitation Techniques
JWTs (JSON Web Tokens) are everywhere in modern web applications. They are convenient, stateless, and easy to implement—which is exactly why they are often implemented incorrectly. Let's examine JWT vulnerabilities commonly found in CTFs and real applications.
Why Are JWTs Vulnerable?
A JWT consists of three parts: a header, payload, and signature. The header and payload are base64-encoded JSON, while the signature verifies the token's integrity. The problem? Developers often trust the header too much or verify the signature incorrectly.
The None Algorithm Attack
The most famous JWT vulnerability is the "none" algorithm attack. Some JWT libraries let the algorithm be set to "none," effectively disabling signature verification.
How it works:
- Decode the JWT header and payload
- Modify the payload, such as changing the user ID or escalating privileges
- Set the algorithm in the header to "none"
- Remove the signature
- Base64-encode and concatenate the parts
In a CTF challenge, it looks like this:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4ifQ.
Notice that there is no signature after the final dot (.). That is the clue.
Algorithm Confusion: HS256 vs RS256
This classic vulnerability exploits the difference between the HS256 (symmetric) and RS256 (asymmetric) algorithms.
Attack method:
- The server uses RS256 with a public/private key pair
- The attacker changes the algorithm to HS256
- The server uses the public key as the HMAC secret during verification
- The attacker signs the token with the public key, which is public by definition
If the server does not strictly enforce its allowed algorithms, it can be tricked into using the public key as an HMAC secret.
Weak Secret Keys
Many developers use weak secrets for JWT signatures. Tools such as jwt_tool and hashcat can crack them with dictionary or brute-force attacks.
Common weak secrets:
- "secret"
- "password"
- An empty string
- A short numeric code
In CTFs, always try cracking the JWT signature first. It is often the intended solution.
Key Injection Through JKU/JWKS
Some JWTs use the jku (JWK Set URL) or jwks (embedded JWK) header parameter to specify where the verification key should come from. If the application does not validate the source:
- Create your own JWK Set
- Host it on your own server
- Modify the JWT header to point to the malicious JWK URL
- Sign the token with your private key
- The server fetches your key and verifies the forged token
Practical JWT Testing Tools
jwt_tool: An all-purpose JWT testing tool that supports automated scans, token manipulation, and cracking.
python3 jwt_tool.py <JWT> -M at # Full test mode
python3 jwt_tool.py <JWT> -C -d wordlist.txt # Cracking
Burp Suite JWT Editor: A browser extension for manipulating JWTs in real time while testing web applications.
hashcat: Used for offline cracking of JWT secrets.
hashcat -a 0 -m 16500 jwt.txt wordlist.txt
Detection and Defense
For defenders:
- Validate the algorithm explicitly—never trust the header
- Use a strong, random secret of at least 256 bits for HS256
- Disable the "none" algorithm
- Validate JKU/JWKS sources against an allowlist
- Consider short expiration times
- Never store sensitive data in the payload—it is only base64!
For bug hunters:
- Check for algorithm confusion vulnerabilities
- Try cracking the secret with common wordlists
- Explore whether JKU/JWKS can be manipulated
- Test for missing expiration validation
- Try the none algorithm—it still works sometimes!
Conclusion
JWTs are powerful but dangerous when implemented incorrectly. Whether you are solving a CTF challenge or conducting a security assessment, understanding these vulnerabilities gives you a major advantage. The key is that the JWT header is user-controlled data—and user-controlled data must never be trusted.
Happy hacking! 🥞