name: jwt-attack-surface description: Audit JWT implementation for algorithm confusion, secret weakness, claim validation issues, and token handling vulnerabilities. Use when reviewing authentication systems using JWT.
JWT Attack Surface Audit
Purpose
Identify JWT implementation vulnerabilities including algorithm confusion, weak secrets, missing validation, and token handling issues.
Focus Areas
- Algorithm Confusion: alg=none, RS256→HS256 confusion
- Weak Secrets: Short/guessable HMAC secrets
- Missing Validation: Signature bypass, claim verification
- Token Handling: Storage, transmission, revocation
- Claim Issues: Expiration bypass, privilege escalation
Critical Vulnerabilities
Algorithm None Attack
// VULNERABLE - accepts "alg": "none"
jwt.verify(token, secret, { algorithms: ['HS256', 'none'] });
// SECURE - explicit algorithm whitelist
jwt.verify(token, secret, { algorithms: ['HS256'] });
RS256 to HS256 Confusion
# If server uses RS256 (asymmetric):
# - Attacker gets public key
# - Signs token with public key using HS256
# - Server verifies with public key as HMAC secret
# VULNERABLE - accepts multiple algorithms
jwt.decode(token, public_key, algorithms=['RS256', 'HS256'])
# SECURE - single algorithm only
jwt.decode(token, public_key, algorithms=['RS256'])
Weak HMAC Secret
// VULNERABLE - short/guessable secret
const secret = "secret123";
jwt.sign(payload, secret);
// SECURE - strong random secret (>= 256 bits)
const secret = crypto.randomBytes(64).toString('hex');
Missing Expiration Check
// VULNERABLE - ignoring exp claim
claims, _ := jwt.Parse(token, keyFunc)
// No expiration validation!
// SECURE - validate expiration
claims, err := jwt.ParseWithClaims(token, &Claims{}, keyFunc)
if err != nil || claims.ExpiresAt.Before(time.Now()) {
return ErrExpired
}
Output Format
findings:
- title: "JWT accepts 'none' algorithm"
severity: critical
attack_scenario: "Attacker crafts unsigned JWT with alg=none, bypasses authentication"
preconditions: "None"
reachability: public
impact: "Complete authentication bypass"
confidence: high
cwe_id: "CWE-327"
affected_assets:
- "src/auth/jwt.rs:45"
- "/api/auth/verify"
Audit Checklist
Token Generation
[ ] Secret is cryptographically random (>= 256 bits)
[ ] Algorithm is explicitly set (not from token)
[ ] Claims include: iat, exp, iss, aud
[ ] Expiration is reasonable (< 24h for access tokens)
[ ] Sensitive data not in payload (use references)
Token Verification
[ ] Algorithm whitelist (single algorithm preferred)
[ ] Signature verification BEFORE parsing claims
[ ] Expiration (exp) validated
[ ] Issuer (iss) validated
[ ] Audience (aud) validated
[ ] Not-before (nbf) validated if present
Token Handling
[ ] Stored in httpOnly cookie (not localStorage)
[ ] Transmitted over HTTPS only
[ ] Revocation mechanism exists
[ ] Refresh token rotation implemented
[ ] Token not leaked in URLs/logs
Attack Scenarios
1. None Algorithm
Header: {"alg": "none", "typ": "JWT"}
Payload: {"sub": "admin", "role": "admin"}
Signature: (empty)
2. Key Confusion (RS256→HS256)
# Get public key from /api/.well-known/jwks.json
# Sign with public key using HS256
# Server uses public key as HMAC secret
3. Weak Secret Brute Force
# Tools: hashcat, jwt_tool
hashcat -m 16500 jwt.txt wordlist.txt
4. Claim Tampering
# Modify claims if signature not verified
{"sub": "user", "role": "user"} → {"sub": "admin", "role": "admin"}
Severity Guidelines
| Issue | Severity |
|---|---|
| alg=none accepted | Critical |
| Algorithm confusion possible | Critical |
| Weak/guessable secret | Critical |
| No signature verification | Critical |
| No expiration validation | High |
| Token in URL/logs | High |
| No issuer/audience validation | Medium |
| Token in localStorage | Medium |
| Long expiration (> 24h) | Low |
KYCo Integration
Register JWT implementation vulnerabilities:
1. Check Active Project
kyco project list
2. Register Finding
kyco finding create \
--title "JWT accepts 'none' algorithm" \
--project PROJECT_ID \
--severity critical \
--cwe CWE-327 \
--attack-scenario "Attacker crafts unsigned JWT with alg=none, bypasses authentication" \
--impact "Complete authentication bypass" \
--assets "src/auth/jwt.rs:45,/api/auth/verify"
3. Import Scanner Results
# Import semgrep JWT rules
semgrep --config p/jwt --sarif -o jwt-audit.sarif .
kyco finding import jwt-audit.sarif --project PROJECT_ID
Common CWE IDs for JWT Issues
- CWE-327: Use of Broken or Risky Cryptographic Algorithm
- CWE-287: Improper Authentication
- CWE-347: Improper Verification of Cryptographic Signature
- CWE-798: Use of Hard-coded Credentials (weak secret)
- CWE-613: Insufficient Session Expiration