Comprehensive JWT Security Guide#
๐ Updated September 12, 2026 โ added the PAN-OS/Panorama CAS algorithm-confusion bypass (CVE-2026-0265) and how a config precondition leaking pre-auth turns patching into a real priority list.
A practitioner’s reference for JSON Web Token security – vulnerabilities, exploitation techniques, attack vectors, implementation flaws, and defense strategies. Covers algorithm confusion, signature bypass, header injection, key confusion, library-specific issues, cryptographic attacks, attack chaining, and secure implementation patterns.
๐งช Try it live: Practice these attacks hands-on in the JWT Attack Playground โ forge alg:none, RS256โHS256 algorithm confusion, and weak-secret tokens, then fire them at a configurable verifier to see what a vulnerable vs. secure server does. Runs 100% in your browser.
Table of Contents#
- Fundamentals
- JWT Structure & Components
- Algorithm Confusion Attacks
- Signature Bypass Techniques
- Header Manipulation
- Payload Tampering
- Cryptographic & Protocol-Level Attacks
- Library-Specific Vulnerabilities
- Attack Chaining
- Implementation Security
- Attack Methodology
- Secure Development Practices
1. Fundamentals#
JWT Overview#
| Component | Purpose | Security Relevance |
|---|
| Header | Algorithm and token type declaration | Algorithm confusion vector |
| Payload | Claims and data | Authorization decisions |
| Signature | Integrity and authenticity proof | Bypass target |
Common Use Cases#
| Application | JWT Role | Attack Impact |
|---|
| Authentication | Identity assertion | Account takeover |
| Authorization | Permission claims | Privilege escalation |
| Information Exchange | Secure data transmission | Information disclosure |
| API Access | Bearer token | Unauthorized access |
| Microservices | Stateless session | Cross-service token reuse |
JWS vs JWE#
| Format | Purpose | Security Consideration |
|---|
| JWS (JSON Web Signature) | Signed tokens – integrity and authenticity | Most common; payload is readable (base64url), not encrypted |
| JWE (JSON Web Encryption) | Encrypted tokens – confidentiality | Payload confidential; format confusion with JWS possible |
2. JWT Structure & Components#
Token Anatomy#
JWT STRUCTURE:
Header.Payload.Signature
Example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
| Parameter | Description | Security Implications |
|---|
alg | Signature algorithm | Algorithm confusion attacks |
typ | Token type | Type confusion, JWS/JWE format confusion |
kid | Key identifier | Path traversal, SQL injection, command injection |
jku | JWK Set URL | SSRF, URL manipulation, external key loading |
jwk | Embedded JSON Web Key | Key injection – attacker embeds own public key |
x5u | X.509 URL | Certificate injection, SSRF |
x5c | X.509 Certificate Chain | Certificate substitution |
Standard Claims#
| Claim | Purpose | Attack Vectors |
|---|
iss (Issuer) | Token origin | Issuer spoofing, substitution attacks |
sub (Subject) | Token subject | User ID manipulation |
aud (Audience) | Intended recipient | Audience bypass, cross-service token reuse |
exp (Expiration) | Token lifetime | Expiry bypass, token persistence |
iat (Issued At) | Issue timestamp | Replay attacks |
nbf (Not Before) | Activation time | Timing bypass |
3. Algorithm Confusion Attacks#
Attack Mechanism#
ALGORITHM CONFUSION FLOW:
1. Server expects RS256 (RSA + SHA256)
2. Attacker changes alg to HS256 (HMAC + SHA256)
3. Server's public RSA key used as HMAC secret
4. Attacker generates valid HMAC signature
5. Server verifies with same key -> bypass
Vulnerable Algorithm Transitions#
| Original Algorithm | Confused Algorithm | Attack Method |
|---|
| RS256/RS384/RS512 | HS256/HS384/HS512 | Public key as HMAC secret |
| ES256/ES384/ES512 | HS256/HS384/HS512 | Public key as HMAC secret |
| PS256/PS384/PS512 | HS256/HS384/HS512 | Public key as HMAC secret |
| Any Algorithm | none | No signature verification |
Exploitation Techniques#
| Attack Vector | Payload Example | Impact |
|---|
| RSA->HMAC | {"alg":"HS256"} + HMAC(payload, rsa_public_key) | Complete authentication bypass |
| Algorithm None | {"alg":"none"} + unsigned token | Total signature bypass |
| None Variants | {"alg":"NoNe"}, {"alg":"NONE"}, {"alg":"nOnE"} | Blacklist bypass on case-insensitive checks |
| Weak Algorithm | {"alg":"HS256"} with known/weak secret | Signature forgery |
CVE-2024-54150: cjwt C Library#
A real-world algorithm confusion in the xmidt-org/cjwt C library. The cjwt_decode() function reads the algorithm from the JWT header without requiring the caller to specify an expected algorithm. The verification function jws_verify_signature() dispatches based on the header-controlled alg value, allowing an attacker to sign with HMAC using the server’s RSA public key.
Key code review red flags:
- Single decode function for both HMAC and RSA with identical call signatures
- Algorithm determined by parsing untrusted JWT header (
cJSON_GetObjectItemCaseSensitive) - No API parameter for caller to restrict accepted algorithms
4. Signature Bypass Techniques#
Direct Signature Attacks#
| Method | Technique | Requirements |
|---|
| Empty Signature | Remove signature section | Vulnerable parser |
| Signature Stripping | Modify to alg: "none" | Missing algorithm validation |
| Brute Force | HMAC secret guessing via hashcat | Weak secret key |
| Dictionary Attack | Common secret wordlists | Predictable secrets |
| decode() vs verify() | Application uses decode-only function | Developer misunderstanding |
Brute Forcing HMAC Secrets#
HMAC BRUTE FORCE WITH HASHCAT:
hashcat -a 0 -m 16500 <JWT_TOKEN> /path/to/jwt.secrets.list
Mode 16500 = JWT signature cracking
Use --show to display previously cracked results
Wordlists: SecLists/Passwords/scraped-JWT-secrets.txt
Key insight (RFC 8725): Human-memorizable passwords MUST NOT be directly used as HMAC keys. Minimum 256 bits of entropy required for HS256.
Signature Validation Flaws#
COMMON VALIDATION ERRORS:
โโโ Missing Algorithm Verification
โ โโโ Accept any algorithm in header
โ โโโ No algorithm allowlist
โ โโโ Default to insecure algorithms
โโโ Improper Key Handling
โ โโโ Same key for multiple algorithms
โ โโโ Public key reuse
โ โโโ Key confusion attacks
โโโ Logic Bypasses
โ โโโ Empty signature acceptance
โ โโโ Null signature handling
โ โโโ Exception swallowing
โโโ decode() vs verify()
โโโ Using jwt.decode() instead of jwt.verify()
โโโ Decoding without signature check
โโโ Trusting decoded payload as authenticated
Audience Verification Bypass (Go jwt-go)#
The dgrijalva/jwt-go library’s VerifyAudience function accepted empty string ("") as a valid audience value, allowing audience verification to succeed when it should fail. Fix was available in v4.0.0-preview1 but not merged to master, leaving most Go projects vulnerable.
Key Identifier (kid) Attacks#
| Attack | Payload | Effect |
|---|
| Path Traversal | "kid":"../../dev/null" | Sign with empty/known file content |
| Path Traversal | "kid":"../../../public.key" | Use predictable file as key |
| URL Injection | "kid":"http://attacker.com/key" | External key loading |
| SQL Injection | "kid":"' UNION SELECT 'known-secret'--" | Return attacker-controlled key from DB |
| Command Injection | "kid":";cat /etc/passwd" | Code execution |
Remediation pattern (kid path traversal):
// VULNERABLE: direct file path from kid
const keyPath = `/keys/${kid}`;
const key = fs.readFileSync(keyPath);
// SECURE: allowlist mapping
const allowedKeys = {
'key-2024-01': '/secure/keys/2024-01.pem',
'key-2024-02': '/secure/keys/2024-02.pem'
};
if (!allowedKeys.hasOwnProperty(kid)) throw new Error('Invalid key');
const key = fs.readFileSync(allowedKeys[kid]);
Remediation pattern (kid SQL injection):
// VULNERABLE: string concatenation
String query = "SELECT key FROM keys WHERE kid = '" + kidValue + "'";
// SECURE: parameterized query
PreparedStatement stmt = conn.prepareStatement("SELECT key FROM keys WHERE kid = ?");
stmt.setString(1, kidValue);
JWK Set URL (jku) Manipulation#
JKU ATTACK CHAIN:
1. Attacker controls jku parameter
2. Points to malicious JWK Set (hosted on attacker server)
3. Server fetches attacker's keys without URL validation
4. Token validates with attacker's key
5. Complete authentication bypass
SSRF CLASSIFICATION: jku fetching = server-side request to attacker URL
Mitigations:
- Disable
jku parameter support entirely (recommended) - Strict URL allowlisting (full URL, not just domain)
- Disable HTTP redirects when fetching JWKS
- Validate URL before any fetch operation
JWK INJECTION ATTACK:
1. Attacker generates own RSA key pair
2. Modifies JWT payload (e.g., role: "admin")
3. Adds own public key in jwk header parameter
4. Sets kid to match the embedded jwk
5. Signs token with own private key
6. Server uses embedded public key to verify -> bypass
REQUIRES: Server accepts jwk parameter without key allowlisting
X.509 Certificate Attacks#
| Vector | Description | Mitigation |
|---|
| Certificate Injection | Supply malicious certificate via x5u | Strict URL validation |
| Self-Signed Certs | Use untrusted certificates | Certificate chain validation |
| Certificate Confusion | Mix certificate types | Explicit algorithm binding |
| x5c Chain Injection | Embed attacker cert chain in header | Validate against trusted root CAs |
6. Payload Tampering#
Claim Manipulation#
| Claim | Attack Example | Impact |
|---|
User ID (sub) | Change to admin user | Horizontal privilege escalation |
Role (role) | Elevate to administrator | Vertical privilege escalation |
Expiration (exp) | Extend lifetime | Persistent access |
Audience (aud) | Change target application | Cross-application attacks (substitution) |
| Username | Change "username":"johndoe" to "username":"admin" | Identity spoofing |
Business Logic Bypasses#
PAYLOAD ATTACK PATTERNS:
โโโ Privilege Escalation
โ โโโ Role claim modification (user -> admin)
โ โโโ Permission array tampering
โ โโโ Group membership changes
โโโ Time-Based Attacks
โ โโโ Expiry extension (exp)
โ โโโ Not-before bypass (nbf)
โ โโโ Issued-at manipulation (iat)
โโโ Cross-Application Attacks (Substitution)
โ โโโ Audience switching (aud)
โ โโโ Issuer spoofing (iss)
โ โโโ Token reuse across services
โ โโโ Cross-JWT confusion (RFC 8725 Section 2.8)
โโโ Indirect Server Attacks
โโโ Claims used in LDAP lookups (injection)
โโโ Claims used in database queries (SQLi)
โโโ Claims containing URLs (SSRF)
7. Cryptographic & Protocol-Level Attacks#
Elliptic Curve Invalid Curve Attacks#
JOSE libraries that fail to validate elliptic curve inputs during ECDH-ES key agreement are vulnerable to invalid curve point attacks. An attacker sends JWEs with invalid curve points and observes cleartext outputs to recover the recipient’s private key.
| Algorithm | Attack | Mitigation |
|---|
| ECDH-ES | Invalid curve point injection | Validate points per NIST SP 800-56A Section 5.6.2.3.4 |
| ES256 | Psychic Signatures (CVE-2022-21449) | Java EC signature with zero values accepted as valid |
JWE-Specific Attacks#
| Attack | Description | Mitigation |
|---|
| JWE Decompression Bomb | Compressed JWE payload expands to exhaust memory | Limit decompression output size |
| Compression Oracle | Ciphertext length leaks plaintext information when compression enabled | Avoid compression before encryption (RFC 8725 Section 3.6) |
| JWS/JWE Format Confusion | Verifier doesn’t check if received JWT is JWS vs JWE; successful decryption treated as signature validation (CVE-2023-51774) | Explicitly check JWT format type |
Hash Iteration DoS#
Libraries that support password-based encryption (PBES2) may accept unreasonable iteration counts, causing CPU exhaustion when processing a maliciously crafted token.
| Parameter | Risk | Mitigation |
|---|
p2c (PBES2 count) | Attacker sets extremely high iteration count | Limit maximum hash iteration count |
Bleichenbacher Attack on RSA-PKCS1#
RSA-PKCS1 v1.5 encryption algorithms are vulnerable to Bleichenbacher’s chosen-ciphertext attack (padding oracle). Prefer RSAES-OAEP.
8. Library-Specific Vulnerabilities#
Historical Vulnerabilities#
| Library | CVE | Vulnerability | Impact |
|---|
| node-jsonwebtoken | CVE-2015-9235 | Algorithm confusion | Authentication bypass |
| node-jsonwebtoken | CVE-2022-23529 | RCE via malicious secretOrPublicKey object | Remote code execution (retracted – requires caller misuse) |
| pyjwt | CVE-2017-11424 | Key confusion | Signature verification bypass |
| php-jwt | CVE-2021-46743 | Algorithm substitution | Authentication bypass |
| jose4j | CVE-2023-51775 | Algorithm confusion | Token forgery |
| xmidt-org/cjwt (C) | CVE-2024-54150 | Algorithm confusion – no caller-specified algorithm | Authentication bypass via HMAC/RSA key confusion |
| dgrijalva/jwt-go (Go) | SNYK-GOLANG-596515 | Audience verification bypass (empty string accepted) | Access restriction bypass |
| Java SE | CVE-2022-21449 | “Psychic Signatures” – EC zero-value signature accepted | Signature validation bypass |
| nimbus-jose-jwt | CVE-2023-51774 | JWS/JWE format confusion | Authentication bypass |
Framework Integration Issues#
FRAMEWORK VULNERABILITIES:
โโโ Express.js/Node.js
โ โโโ jsonwebtoken algorithm confusion
โ โโโ jwt.decode() vs jwt.verify() misuse
โ โโโ Middleware bypass techniques
โ โโโ CVE-2022-23529 (secretOrPublicKey object injection)
โ โโโ Error handling flaws
โโโ Django/Python
โ โโโ PyJWT verification bypasses
โ โโโ Algorithm None attacks
โ โโโ Key handling issues
โ โโโ Flask-JWT-Extended misconfiguration
โโโ Spring Boot/Java
โ โโโ JJWT library flaws
โ โโโ Algorithm validation bypass
โ โโโ CVE-2022-21449 (EC Psychic Signatures)
โ โโโ Token sidejacking defenses (OWASP)
โ โโโ Key injection vulnerabilities
โโโ ASP.NET/C#
โ โโโ System.IdentityModel flaws
โ โโโ Algorithm confusion
โ โโโ Certificate validation bypass
โโโ Go
โโโ dgrijalva/jwt-go audience bypass
โโโ Master branch vs tagged release divergence
โโโ VerifyAudience empty string acceptance
PAN-OS / Panorama CAS algorithm confusion (CVE-2026-0265)#
Pre-auth JWT signature bypass in PAN-OS and Panorama. Palo Alto classified it CWE-347 (improper verification of a cryptographic signature); the root cause is algorithm confusion in pan_auth_verify. An unauthenticated remote attacker forges a JWT and logs in as any user the firewall trusts โ GlobalProtect portal attacks compromise VPN user sessions, management interface attacks compromise the PAN-OS administrator account. Reported by Harsh Jaiswal of HacktronAI.
The precondition is everything for scoping: the vulnerable path is only reachable when Cloud Authentication Service (CAS) is attached to an authentication profile. Without CAS on the profile, the code never runs. So your exposure question isn’t “do I run PAN-OS,” it’s “which of my authentication profiles have CAS attached, and are those profiles bound to a GlobalProtect portal or an admin role.”
Fixed in 10.2.18+, 11.1.15+, 11.2.12+, 12.1.7+. If you can’t patch, detach CAS โ replace it with SAML, RADIUS, LDAP, or local auth on every affected profile, which neutralizes the bug on that profile.
Two things worth flagging beyond the bug itself.
Bishop Fox built a detection script that returns a definitive vulnerable/not-vulnerable verdict per GlobalProtect portal from a single anonymous HTTP request, by pulling both the CAS precondition and the PAN-OS version out of the same unauthenticated prelogin response. That’s the pattern to steal for your own fleet work: when a bug has a configuration precondition, look for a pre-auth response that leaks the configuration state, and you can turn “patch everything” into an actual prioritized list. Cloud-managed SaaS assets shouldn’t be affected; undetermined results need an admin to review.
And on severity โ Palo Alto rated the management-interface case 7.2 High and gave the GlobalProtect portal a separate, lower score. Jaiswal publicly disputed the rating. Worth remembering when you’re triaging from vendor CVSS alone: a vendor scoring a pre-auth authentication bypass as a 7.2 is making assumptions about exposure that may not match your environment. Score it against your deployment.
9. Attack Chaining#
JWT Bypass to RCE#
CTF EXAMPLE: JWT None Algorithm -> Admin Panel -> SSTI -> RCE
Chain:
1. Decode JWT, identify role claim ("user")
2. Set alg to "none", change role to "admin", strip signature
3. Access admin panel with forged token
4. Discover input field vulnerable to Jinja2 SSTI
5. Execute RCE via Python class hierarchy traversal:
{โ% for x in ().__class__.__base__.__subclasses__() %}
{โ% if "warning" in x.__name__ %}
{โ{x()._module.__builtins__["__import__"]("os").popen('whoami').read()}}
{โ% endif %}
{โ% endfor %}
6. Read flag from filesystem
Impact: JWT auth bypass -> privilege escalation -> code execution
Common JWT Attack Chains#
| Initial Vulnerability | Escalation | Final Impact |
|---|
| JWT none algorithm | Admin panel access | Privilege escalation |
| JWT kid path traversal | Read sensitive files | Information disclosure / auth bypass |
| JWT kid SQL injection | Extract signing keys from DB | Full token forgery |
| JWT jku injection | SSRF to internal services | Internal network access |
| JWT weak secret + brute force | Forge tokens for any user | Account takeover |
| JWT alg confusion + claim modification | Admin role assignment | Full application compromise |
10. Implementation Security#
Secure JWT Verification#
| Security Control | Implementation | Common Mistakes |
|---|
| Algorithm Validation | Strict allowlist (whitelist, not blacklist) | Accept any algorithm; blacklist none with case-sensitive check |
| Key Management | Rotate regularly, separate keys per algorithm | Reuse across algorithms |
| Signature Verification | Mandatory for all tokens; use verify() not decode() | Optional or bypassable; using decode-only functions |
| Claim Validation | Validate all critical claims server-side | Trust payload data |
| Format Type Check | Explicitly verify JWS vs JWE format | Accept any JWT structure |
Token Sidejacking Defense (OWASP)#
TOKEN FINGERPRINTING:
1. On authentication, generate random string (50 bytes, SecureRandom)
2. Send raw value as hardened cookie:
__Secure-Fgp=<value>; SameSite=Strict; HttpOnly; Secure
3. Store SHA-256 hash of value in JWT claim (userFingerprint)
4. On each request:
a. Read fingerprint cookie
b. Hash it with SHA-256
c. Compare to JWT claim
d. Reject token if mismatch
BENEFIT: Even if JWT is stolen, attacker lacks the HttpOnly cookie
NOTE: Avoid IP-based fingerprinting (changes on mobile networks, GDPR concerns)
Token Revocation Strategies#
| Strategy | Mechanism | Trade-off |
|---|
| Short-lived tokens | Set exp to 15 minutes max | Frequent re-authentication |
| Token denylist (DB) | SHA-256 digest stored in revocation table | Reintroduces server state |
| Refresh token rotation | Issue new access token via refresh endpoint | Refresh token must be secured |
| Cookie clearing on logout | Clear JWT from sessionStorage + cookie | Only effective if user initiates logout |
Key Management Best Practices#
SECURE KEY PRACTICES:
โโโ Key Generation
โ โโโ Cryptographically random (SecureRandom, os.urandom)
โ โโโ Sufficient entropy (256+ bits for HMAC)
โ โโโ Algorithm-specific requirements
โ โโโ Never use human-memorizable passwords as HMAC keys
โโโ Key Storage
โ โโโ Hardware security modules (HSM)
โ โโโ Cloud KMS (AWS KMS, Azure Key Vault, GCP KMS)
โ โโโ Environment variables (development only)
โ โโโ Never hardcode in source code
โโโ Key Rotation
โ โโโ Regular rotation schedule
โ โโโ Grace periods for old keys (support both during transition)
โ โโโ Emergency rotation procedures
โโโ Key Distribution
โ โโโ Secure channels only (HTTPS)
โ โโโ JWK Set endpoints (/.well-known/jwks.json)
โ โโโ Certificate-based PKI
โโโ Key-Algorithm Binding
โโโ Each key used with exactly one algorithm
โโโ Separate keys for signing vs encryption
โโโ Validated at cryptographic operation time
11. Attack Methodology#
Reconnaissance Phase#
| Target | Information Gathering | Tools |
|---|
| JWT Structure | Token analysis, header/payload decode | JWT.io, jwt_tool, CyberChef |
| Algorithm Detection | Header inspection | Burp Suite, manual analysis |
| Key Discovery | Public key extraction, JWKS endpoints | Certificate analysis, /.well-known/jwks.json |
| Implementation Details | Error message analysis, library fingerprinting | Fuzzing, invalid tokens |
| Framework Detection | Wappalyzer, BuiltWith | Technology stack identification |
Exploitation Workflow#
ATTACK SEQUENCE:
โโโ Token Acquisition
โ โโโ Login with valid credentials
โ โโโ Social engineering
โ โโโ Token leakage (logs, URLs, Referer headers)
โโโ Token Analysis
โ โโโ Decode header and payload (base64url)
โ โโโ Identify critical claims (role, sub, aud)
โ โโโ Determine algorithm
โ โโโ Check for optional header params (kid, jku, jwk)
โโโ Vulnerability Testing
โ โโโ Algorithm none (with case variants)
โ โโโ Algorithm confusion (RS256 -> HS256)
โ โโโ Signature removal / empty signature
โ โโโ Weak secret brute force (hashcat -m 16500)
โ โโโ kid injection (path traversal, SQLi)
โ โโโ jku/jwk injection
โ โโโ Claim manipulation (role, sub, exp)
โ โโโ decode() vs verify() check
โโโ Escalation
โ โโโ Forge admin tokens
โ โโโ Chain with other vulns (SSTI, SSRF, SQLi)
โ โโโ Cross-service token reuse
โโโ Impact Assessment
โโโ Authentication bypass
โโโ Privilege escalation
โโโ Data access
โโโ Remote code execution (via chaining)
| Tool | Purpose | Features |
|---|
| jwt_tool | JWT manipulation & testing | Algorithm attacks, claim fuzzing, automated scanning |
| Burp JWT Editor | Token editing & signing | Real-time editing, key generation, re-signing |
| JWT Scanner (Burp) | Automated vulnerability scanning | None algorithm, CVE-2022-21449, key confusion, public key forging |
| JOSEPH (Burp) | JOSE pentesting helper | Bleichenbacher MMA, key confusion, signature exclusion |
| hashcat (-m 16500) | HMAC secret brute force | Dictionary/brute force attacks on JWT signing keys |
| c-jwt-cracker | HMAC brute force (C) | Fast native cracking |
| JWT2John | Password cracking prep | Extract JWT for John the Ripper |
| jwtXploiter | JWT security testing | Multiple attack vectors |
| jwt-pwn | JWT security testing scripts | Python-based testing suite |
| Snyk | SAST for JWT misuse | Detects jwt.decode() misuse, vulnerable library versions |
12. Secure Development Practices#
Implementation Checklist#
| Security Control | Verification | Risk Level |
|---|
| Algorithm Allowlist | Explicitly define allowed algorithms (whitelist) | Critical |
| Signature Verification | Mandatory for all tokens; use verify() | Critical |
| Key Management | Secure generation, storage, rotation; 256+ bit entropy | Critical |
| Key-Algorithm Binding | Each key used with exactly one algorithm | Critical |
| Claim Validation | Validate iss, aud, exp, nbf, sub | High |
| Format Type Check | Verify JWS vs JWE explicitly | High |
| Header Parameter Restrictions | Reject/ignore jku, jwk, x5u unless explicitly needed | High |
| kid Validation | Allowlist or parameterized lookups only | High |
| Token Lifetime | Short expiration (15 min access tokens) | High |
| Token Fingerprinting | Bind tokens to client context (hardened cookie) | Medium |
| Error Handling | No information leakage in error responses | Medium |
| Token Revocation | Implement denylist for logout support | Medium |
| Compression | Never compress before encryption | Medium |
| HTTPS Transport | Tokens transmitted only over TLS | Medium |
RFC 8725 Best Practices Summary#
RFC 8725 / draft-sheffer-oauth-rfc8725bis KEY REQUIREMENTS:
โโโ Algorithm Verification
โ โโโ Libraries MUST let caller specify supported algorithms
โ โโโ MUST NOT use algorithms not in the specified set
โ โโโ Each key MUST be used with exactly one algorithm
โ โโโ MUST be checked at cryptographic operation time
โโโ Cryptographic Hygiene
โ โโโ Validate all cryptographic operations (including nested JWTs)
โ โโโ Validate elliptic curve inputs (invalid curve attacks)
โ โโโ Keys MUST have sufficient entropy (256+ bits)
โ โโโ Avoid compression before encryption
โ โโโ Use UTF-8 encoding exclusively
โโโ Claim Validation
โ โโโ Validate issuer and subject
โ โโโ Use and validate audience
โ โโโ Do NOT trust received claims for server-side operations
โ โโโ Use explicit typing (typ header) to prevent cross-JWT confusion
โโโ Format Safety (RFC 8725bis additions)
โ โโโ Limit hash iteration count (PBES2 p2c parameter)
โ โโโ Check JWT format type (JWS vs JWE)
โ โโโ Limit JWE decompression size
โโโ General
โโโ Use RSAES-OAEP instead of RSA-PKCS1 v1.5
โโโ Implement ECDSA with deterministic nonces (RFC 6979)
โโโ Use mutually exclusive validation rules for different JWT types
Framework-Specific Guidance#
SECURE IMPLEMENTATION PATTERNS:
โโโ Node.js/Express
โ โโโ Use jsonwebtoken with explicit algorithms option
โ โโโ ALWAYS use jwt.verify(), NEVER jwt.decode() for auth
โ โโโ Implement proper error handling (no stack traces)
โ โโโ Validate all claims explicitly
โ โโโ Keep jsonwebtoken >= v9.0.0
โโโ Python/Django/Flask
โ โโโ PyJWT with algorithms parameter (whitelist)
โ โโโ Always verify signature before trusting claims
โ โโโ Custom middleware for validation
โ โโโ Secure key storage (environment variables / KMS)
โ โโโ Flask-JWT-Extended with secure cookie configuration
โโโ Java/Spring Boot
โ โโโ Spring Security JWT support with algorithm validation
โ โโโ Token sidejacking with fingerprint cookies (OWASP pattern)
โ โโโ Token denylist for revocation
โ โโโ JWK Set endpoints for key distribution
โ โโโ Ensure JDK patched for CVE-2022-21449
โ โโโ Use auth0/java-jwt or nimbus-jose-jwt (latest)
โโโ .NET/ASP.NET Core
โ โโโ Microsoft.IdentityModel.JsonWebTokens
โ โโโ TokenValidationParameters (strict configuration)
โ โโโ Strict algorithm validation
โโโ Go
โโโ Use golang-jwt/jwt (not dgrijalva/jwt-go)
โโโ Validate audience explicitly
โโโ Pin to tagged releases, not master branch
Security Testing Strategy#
| Test Category | Test Cases | Expected Result |
|---|
| Algorithm Tests | none (all case variants), HS256<->RS256, invalid | Reject all invalid algorithms |
| Signature Tests | Missing, empty, invalid, decode-only | Reject all invalid signatures |
| Claim Tests | Expired, wrong audience, wrong issuer, missing | Validate all critical claims |
| Header Tests | kid injection (traversal, SQLi), jku/jwk manipulation | Reject malicious parameters |
| Key Tests | Weak HMAC secret, brute force, public key confusion | Resist all key attacks |
| Format Tests | JWE sent where JWS expected, nested JWT | Explicit format validation |
| Chaining Tests | JWT bypass + secondary exploitation | Defense in depth at each layer |
Key Takeaways#
- Algorithm Validation: Always use explicit algorithm allowlists – never blacklists (case-variant bypass)
- Signature Verification: Use
verify(), never decode() for authentication decisions - Key Management: Use separate keys per algorithm, 256+ bits entropy, never human-memorable passwords
- Claim Validation: Validate all security-relevant claims (iss, aud, exp, nbf, sub)
- Header Restrictions: Reject or strictly validate jku, jwk, kid, x5u parameters
- Format Awareness: Explicitly check JWS vs JWE format to prevent confusion attacks
- Token Binding: Use fingerprint cookies to mitigate token sidejacking
- Library Updates: Keep JWT libraries current; review CVE history before adopting new libraries
- Defense in Depth: JWT bypass alone may not be critical; prevent secondary exploitation (SSTI, SQLi, SSRF)
- RFC 8725 Compliance: Follow IETF Best Current Practices as minimum security baseline
References#
Keep an eye on emerging JWT attack techniques, library vulnerabilities, and RFC 8725bis updates.