Audit JWT implementation for algorithm confusion, secret weakness, claim validation issues, and token handling vulnerabilities. Use when reviewing authentication systems using JWT.
Scanned 2/12/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
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
```javascript
// 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
```python
# 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
```javascript
// 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
```go
// 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
```yaml
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
```bash
kyco project list
```
### 2. Register Finding
```bash
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
```bash
# 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
No comments yet. Be the first to comment!