JWT Vulnerabilities: Complete Testing Guide

Master JSON Web Token vulnerabilities with complete testing methodology covering algorithm confusion attacks, signature bypass, none algorithm exploitation, key injection, kid parameter attacks, and practical exploitation techniques with real-world examples.

Jan 9, 2026 - 03:56
Jan 9, 2026 - 04:14
JWT Vulnerabilities: Complete Testing Guide

JSON Web Tokens have become ubiquitous in modern web application authentication. Their stateless nature eliminates the need for server-side session storage. Their compact format enables efficient transmission across networks. Their cryptographic signatures provide integrity verification.

Yet this elegance masks a minefield of vulnerabilities.

A single misconfiguration in JWT implementation can hand attackers complete authentication bypass. A developer mistake in algorithm handling can enable token forgery with a null byte. A forgotten validation of the exp claim can permit replay attacks years after token expiration.

The vulnerabilities aren't theoretical. In 2025 alone, six critical CVEs targeting JWT implementations were disclosed, affecting millions of users across cloud platforms and enterprise systems. Algorithm confusion attacks continue to compromise production systems. The "none" algorithm bypass persists despite decades of known vulnerability.

This is the complete guide to JWT vulnerabilities. This is everything you need to know to test, exploit, and fix broken JWT implementations.

Understanding JWT Structure: The Foundation of Exploitation

A JWT consists of three Base64URL-encoded components separated by dots:

header.payload.signature

The header contains metadata instructing the server how to validate the token. The critical alg parameter specifies the signing algorithm. The typ parameter indicates the token type. Optional parameters like kid (Key ID) or jku (JWK Set URL) influence key selection.

The payload contains the claims—data assertions about the subject. Standard claims include iss (issuer), sub (subject), aud (audience), exp (expiration), nbf (not before), and iat (issued at). Additional custom claims contain application-specific data.

The signature is calculated from the encoded header and payload using a secret or private key. This signature ensures that neither header nor payload has been modified after signing.

This structure is inherently vulnerable because the header is decoded and processed before signature verification occurs. Attackers exploit this timing to manipulate which algorithm is used for verification.

The 15 Critical JWT Vulnerabilities

1. Algorithm Confusion (RS256 to HS256)

This is the most impactful JWT vulnerability. It exploits the distinction between asymmetric (RS256) and symmetric (HS256) algorithms.

RSA (RS256) uses a private key for signing and a public key for verification. The public key is widely distributed. The private key remains secret.

HMAC (HS256) uses a single secret for both signing and verification.

The vulnerability occurs when a server that uses RS256 accepts JWTs signed with HS256. The attack works as follows:

Obtain a valid JWT signed with RS256. Extract the public key from the server's JWKS endpoint or certificate.

Modify the JWT payload to grant yourself elevated privileges (admin role, user ID change, etc.). Change the alg header from RS256 to HS256. Sign the forged JWT using HMAC with the RSA public key as the secret.

If the server doesn't validate the algorithm parameter or uses the public key as an HMAC secret, the forged token validates successfully.

The root cause is that JWT libraries often provide algorithm-agnostic verification methods. A single verify() method handles all algorithms. If the server doesn't explicitly specify which algorithm to expect, it implicitly trusts the algorithm specified in the token header—which is user-controlled and hasn't been verified yet.

Real-world impact: Attackers achieve complete authentication bypass, assuming any user identity and granting themselves admin access.

Proof of Concept:

# Extract public key from server
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > cert.pem
openssl x509 -pubkey -in cert.pem -noout > pubkey.pem

# Use jwt_tool to perform algorithm confusion
python3 jwt_tool.py eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... -C -k pubkey.pem

2. The None Algorithm

The JWT specification includes a "none" algorithm allowing unsigned tokens. This was intended for debugging or unsecured scenarios.

Many early JWT library versions enabled the none algorithm by default. Vulnerable servers accept tokens with alg: "none" without verifying any signature.

The attack is trivially simple:

Decode an existing JWT. Modify the payload to grant yourself admin access. Set alg to "none" in the header. Remove the signature entirely (keep the trailing dot, but send empty signature). Send the modified token.

Modern JWT libraries disable the none algorithm by default. However, many legacy systems remain vulnerable. Some modern libraries still accept none if developers explicitly enable it.

Real-world impact: Complete authentication bypass requiring no cryptographic knowledge.

Detection:

# Test with Burp JWT extension
# Modify token, set alg to "none", remove signature
# Observe whether server accepts unsigned token

3. Weak Secrets

HMAC-based JWTs can be brute-forced if the secret is weak or commonly-used.

Common weak secrets include "secret", "password", "admin", "key123", or empty strings. Many developers use default secrets from documentation or examples without changing them.

If a server uses HS256 with a weak secret, attackers can:

Obtain a valid JWT. Hash dictionary words and common passwords with HS256. When a match is found, use the cracked secret to forge new tokens with elevated privileges.

Tools like hashcat and John the Ripper can crack weak HMAC secrets at billions of hashes per second.

Real-world impact: Complete token forgery if weak secrets are discovered.

Detection:

# Use jwt_tool to brute-force weak secrets
python3 jwt_tool.py -t -wl /path/to/wordlist

# Try common secrets manually
jwt_tool.py -t -k "secret"
jwt_tool.py -t -k "password"
jwt_tool.py -t -k "admin"

4. None Algorithm Bypass with Null Key

Some servers expect RSA signatures but fail to configure the HMAC key. When receiving an HS256 token with an HMAC signature using a null byte or empty string as the secret, the signature validates successfully.

Attack:

# Sign JWT with empty string as secret
python3 jwt_tool.py -t -p '' -a HS256
# Or with null byte
python3 jwt_tool.py -t -p '\x00' -a HS256

The vulnerability occurs because the server attempts to validate with null or empty keys that it never explicitly rejected.

5. Key ID (kid) Parameter Injection

The kid parameter identifies which key to use for verification. If the server retrieves keys based on kid without validation, attackers can manipulate this parameter.

File-based kid injection:

Original: "kid": "key/production.pem"
Attack: "kid": "../../../etc/passwd"
Attack: "kid": "/dev/null"

If the kid is directly concatenated into file paths, attackers can:

Read arbitrary files by pointing kid to system files. Sign tokens with empty strings if kid points to /dev/null. Execute code if kid is used in command execution contexts.

Database-based kid injection:

Original query: SELECT key FROM keys WHERE id = '12345'
Injected: SELECT key FROM keys WHERE id = '12345' OR 1=1 --'

SQL injection via kid allows attackers to select arbitrary keys for verification.

Real-world impact: File disclosure, SQL injection, and RCE depending on how kid is used.

6. JKU (JWK Set URL) Injection

JKU specifies a URL pointing to a JSON Web Key Set containing the public keys for verification.

Vulnerable servers fetch this URL without validation and use keys from the response to verify signatures. Attackers can:

Host a malicious JWKS containing their own public keys. Change the jku parameter to point to attacker-controlled servers. Create self-signed certificates and sign forged JWTs.

The server then uses the attacker's key to verify the attacker's signature, validating the forged token.

Real-world impact: Complete authentication bypass via self-signed key injection.

Detection:

# Modify jku to point to attacker server
# Create JWKS with your own public key
# Sign forged JWT with your private key
# Server validates using attacker's public key from jku

7. X5U (X.509 URL) Certificate Injection

Similar to jku, the x5u parameter specifies a URL containing X.509 certificates. Vulnerable servers fetch and use these certificates without validation.

Attack:

{
  "alg": "RS256",
  "x5u": "https://attacker.com/cert.pem"
}

The server fetches the certificate from the attacker's URL and uses it to verify the signature—a signature the attacker created with their own key.

8. JWK Header Parameter Injection

Instead of fetching keys from external URLs, some servers accept keys embedded directly in the jwk header parameter.

Attack:

{
  "alg": "RS256",
  "jwk": {
    "kty": "RSA",
    "n": "",
    "e": "AQAB"
  }
}

The server uses the attacker's public key to verify the signature—which the attacker created with their private key.

This is extraordinarily dangerous because the server uses whatever key is provided in the token itself.

9. Claims Not Validated Properly

Even with correct signature verification, applications often fail to validate claims properly.

Expiration (exp) bypass: Tokens without exp claims never expire. Servers that don't check exp accept tokens valid indefinitely.

Not-before (nbf) bypass: Tokens without nbf claims are valid immediately. Servers accepting tokens before nbf are exploitable.

Audience (aud) bypass: Cross-service relay attacks use tokens intended for one service to access another. If aud isn't validated, a token issued for service-a can access service-b.

Issuer (iss) bypass: Forged tokens with wrong issuers are accepted if not validated.

Custom claim validation failures: User IDs, roles, permissions, and other custom claims might not be validated against server-side state.

Real-world impact: Privilege escalation, lateral movement, and extended unauthorized access.

Test cases:

# Remove exp claim
# Server should reject, but might accept

# Change aud from "service-a" to "service-b"
# Attempt cross-service access

# Modify user role from "user" to "admin"
# Server accepts without backend validation

10. BOLA/BFLA via JWT Claims

Broken Object Level Authorization (BOLA) and Broken Function Level Authorization (BFLA) vulnerabilities often stem from over-trusting JWT claims.

BOLA example:

{
  "sub": "user123",
  "org_id": "org456"
}

Attacker changes org_id to "org789" and accesses victim organization data.

BFLA example:

{
  "sub": "user123",
  "role": "user",
  "permissions": ["read"]
}

Attacker changes role to "admin" and permission to ["read", "write", "delete"], accessing admin functions.

The vulnerability occurs when servers trust claims without backend validation.

11. Replay Attacks and Token Reuse

JWTs without unique identifiers (jti claim) or proper validation can be replayed indefinitely.

Attack scenario:

Intercept a valid JWT. Use it to perform sensitive operations (fund transfer, access sensitive data). Replay the same token to repeat the operation.

Servers should use jti (JWT ID) to track used tokens and prevent replays. Without jti tracking, the same token can be used repeatedly.

Additional risk: Long token lifespans (24+ hours) amplify replay attack impact. Tokens should have short lifespans (15 minutes) with refresh tokens for extended sessions.

12. Signature Verification Disabled

Some applications confuse decode() and verify() methods in JWT libraries.

Node.js jsonwebtoken example:

// Vulnerable: Uses decode instead of verify
const token = jwt.decode(req.headers.authorization);

// Secure: Uses verify
const token = jwt.verify(req.headers.authorization, secret);

The decode() method extracts claims without verifying the signature. Applications using decode() accept any token, even completely invalid ones.

Real-world impact: Complete authentication bypass.

13. Token Leakage and Exposure

JWTs often contain sensitive information in the payload. Because payloads are only Base64-encoded (not encrypted), they're readable by anyone with the token.

Sensitive data in JWT payloads:

  • User IDs and email addresses
  • Internal organization IDs
  • User roles and permissions
  • Phone numbers and personal information
  • API keys or secrets

Any attacker with access to the token (via network sniffing, browser history, or logs) can extract this information.

Solutions:

Use JWE (JSON Web Encryption) to encrypt payloads. Avoid storing sensitive data in tokens. Use short-lived tokens with stateful servers for sensitive claims.

14. Token Timing Attacks (Back-to-Future)

The "Back to the Future" vulnerability allows creating valid tokens dated in the future by manipulating client time.

Attack:

Set system clock to future date (e.g., 2 days ahead). Request JWT with nbf set to current future time. Reset system clock to present. Use the token immediately—nbf validation passes because iat/nbf were set relative to the future date.

The vulnerability requires the server to trust client-provided timing information.

15. CVE-2025-4692 and Recent JWT Library Vulnerabilities

Six critical CVEs disclosed in 2025 affected popular JWT implementations:

CVE-2025-4692: Cloud platform algorithm confusion flaw enabling unauthorized token creation.

CVE-2025-30144: Library bypass allowing signature verification to be skipped.

CVE-2025-27371: ECDSA public key recovery enabling token forgery.

These CVEs demonstrate that JWT vulnerabilities remain prevalent in modern implementations.

JWT Testing Methodology

Step 1: Token Collection and Decoding

Intercept JWTs in Burp Suite or your proxy. Decode using jwt.io or jwt_tool:

python3 jwt_tool.py -t eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Examine the header, payload, and signature. Note the algorithm, claims, and any unusual parameters (jku, x5u, kid, jwk).

Step 2: Signature Verification Testing

Test whether servers actually verify signatures:

# Remove signature entirely
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.

# Modify payload and keep original signature
# Modify only signature
# Observe whether server accepts invalid tokens

Step 3: Algorithm Confusion Testing

Test each algorithm combination:

# Test none algorithm
# Test HS256 with public key (if RS256 in use)
# Test RS256 with HMAC key
# Test ECDSA confusion
# Test algorithm switching

Create test tokens signed with each algorithm against the target.

Step 4: Weak Secret Testing

If HS256 is used, attempt brute-forcing:

python3 jwt_tool.py -t -wl wordlist.txt
hashcat -m 16500 jwt_hash wordlist.txt

Step 5: Claims Manipulation Testing

Test each claim modification:

# Change user ID
# Modify role/permission claims
# Remove expiration
# Remove not-before
# Change audience
# Change issuer
# Add custom claims
# Observe server response for each

Step 6: Header Parameter Injection

Test special header parameters:

# Modify kid parameter
# Inject jku URL to attacker server
# Inject x5u URL to attacker server
# Inject jwk with attacker key
# Inject custom parameters

Step 7: Cross-Service Token Testing

In microservice architectures, test whether tokens for one service work on others:

# Obtain token for service-a
# Use on service-b, service-c, etc.
# Observe whether aud claim prevents cross-service access

Testing Tools

Burp Suite JWT Editor Extension provides GUI-based JWT manipulation and algorithm testing.

jwt_tool offers comprehensive command-line JWT testing:

python3 jwt_tool.py -t -C  # Claims testing
python3 jwt_tool.py -t -k secret  # Weak secret testing
python3 jwt_tool.py -t -wl wordlist.txt  # Brute-force

jwt.io decodes and verifies tokens online (use only with non-sensitive tokens).

JOSEPH Burp Extension specifically targets algorithm confusion attacks.

Hashcat cracks weak HS256 secrets at scale.

rsa_sign2n recovers ECDSA public keys from token pairs.

PentesterLab offers hands-on JWT exploitation exercises.

PortSwigger WebSecurity Academy provides comprehensive JWT vulnerability labs.

Real-World Exploitation Example

Scenario: Target uses RS256 but accepts algorithm switching.

# 1. Obtain valid JWT
# 2. Decode to extract header and payload
# 3. Modify payload: {"sub":"user123","role":"user"} to {"sub":"user123","role":"admin"}
# 4. Get server's public key from JWKS endpoint
# 5. Create new JWT with HS256 algorithm
# 6. Sign with HMAC using public key as secret
# 7. Send forged token
# 8. Server accepts because algorithm is mutable
# 9. Attacker now has admin access

Remediation and Best Practices

✅ Use strong secrets: Minimum 32 random bytes for HS256 keys.

✅ Explicitly specify algorithms: Tell JWT libraries exactly which algorithm to expect.

✅ Use asymmetric algorithms: RS256 or ES256 preferred over HS256.

✅ Validate all claims: iss, aud, exp, nbf, and custom claims.

✅ Use short-lived tokens: 15-minute expiration with refresh tokens.

✅ Implement JTI tracking: Prevent token replay with unique identifiers.

✅ Encrypt sensitive data: Use JWE instead of JWS for confidential claims.

✅ Update libraries: Keep JWT libraries current with security patches.

✅ Disable unnecessary algorithms: Explicitly reject "none" and unneeded algorithms.

✅ Monitor for anomalies: Alert on tokens with unusual claims or frequent algorithm changes.

Conclusion

✅ JWT vulnerabilities continue to enable authentication bypass and privilege escalation in modern applications. Algorithm confusion, weak secrets, and claims validation failures remain endemic despite best practices being well-documented.

✅ Testing for JWT vulnerabilities requires systematic assessment across algorithm support, signature verification, claims validation, and parameter injection. Using appropriate tools like jwt_tool and Burp Suite extensions enables efficient vulnerability discovery.

✅ Organizations deploying JWTs must understand the inherent risks and implement rigorous testing, careful configuration, and continuous monitoring to prevent exploitation.