jwt-security-review
Audit JSON Web Token implementations for algorithm confusion, weak secrets, missing validation, and token lifecycle flaws. Use when a codebase or API uses JWTs for auth.
Savant verdict: Pending analysis
Imported from the source hub; Savant's analysis is still running.
Live evaluation
Not evaluated yet. Workspaces can request a live evaluation.
Safety (NVIDIA SkillSpector)
Scan pending.
Structure
- No license declaredConfirm you may reuse this skill before importing it into your repository.
SKILL.md
---
name: jwt-security-review
description: Audit JSON Web Token implementations for algorithm confusion, weak secrets, missing validation, and token lifecycle flaws. Use when a codebase or API uses JWTs for auth.
---
# JWT Security Review
Review JWT-based authentication end to end.
## Review Areas
### Algorithm Handling
- Pin the expected algorithm server-side; reject `alg: none` outright
- **RS256→HS256 confusion**: if the server verifies HMAC using the public key as the secret, an attacker can forge tokens. Confirm verification uses the correct key type per algorithm
- Watch for `jku`/`x5u` header injection where the server fetches keys from an attacker-controllable URL
- `kid` injection: path traversal or SQL/Command injection in key lookup
### Key and Secret Strength
- HS256 secrets: ≥32 bytes of entropy, not from wordlists (`jwt-tools` crack mode)
- Keys rotated; old keys revoked rather than just unused
### Claims Validation
- `exp` and `nbf` enforced, clock skew bounded
- `iss` and `aud` validated against expected values
- Reject tokens with unexpected/extra privileged claims (e.g., `admin: true`) — parse then validate allowlist
- Don't trust client-controlled `role`/`uid` claims if a server-side lookup exists
### Token Lifecycle
- Refresh tokens: rotation with reuse detection; stored hashed server-side
- Revocation path exists for logout/password change/admin force-logout
- Access tokens short-lived (≤15 min); no long-lived bearer tokens
- Tokens not persisted in localStorage if XSS surface exists; prefer httpOnly cookies with CSRF protection
- `sub` is stable and unambiguous (user ID, not email that can change)
### Common Code Smells
```
jwt.decode(token) // decode ≠ verify: signature never checked
jwt.verify(token, key) // no algorithms option pinned
jwt.verify(token, key, { algorithms: ['*'] })
```
## Test Cases
1. Remove the signature; send `alg: none` token
2. Flip `alg` to HS256 signed with the public key
3. Expired/missing `exp`, wrong `iss`/`aud`
4. Tampered claims with valid signature (e.g., escalate role)
5. Replay a rotated refresh token — should invalidate the family
## Output
Findings with token samples (redacted), affected code paths, and remediation per issue.