BytePane

JWT Security 2026 — Algorithm Comparison, Vulnerabilities, Best Practices

Short answer: Use EdDSA (Ed25519) for new systems — fast, secure, modern. Use RS256 for OAuth/OIDC compatibility. Avoid HS256 in distributed systems. NEVER accept alg=none. The 12 most common JWT vulnerabilities are listed below with exploitation pattern + mitigation. Always upgrade libraries (jose 5+, jsonwebtoken 9+, PyJWT 2+) — older versions had alg=none bugs.

JWT signing algorithms — full comparison

AlgorithmTypeKey sizeSign / Verify speedRecommended?Notes
HS256HMAC + SHA-256256-bit shared secretVery fast / Very fastOK for monolithVulnerable if secret leaks; cannot be public
HS384/HS512HMAC + SHA-384/512384/512-bit secretFast / FastOKMarginally more secure than HS256
RS256RSA-PKCS1-v1_5 + SHA-2562048-bit minimum (4096 preferred)Slow / FastCommon for OAuth/OIDCVulnerable to algorithm confusion if HS256 also accepted
RS384/RS512RSA-PKCS1-v1_5 + SHA-384/5122048-bit minSlow / FastSame as RS256Same vulnerability profile
PS256RSA-PSS + SHA-2562048-bit minSlow / FastBetter than RS256PSS padding — provably more secure than PKCS1-v1_5
ES256ECDSA P-256 + SHA-256256-bit elliptic curveFast / FastModern choiceSmaller signatures than RS256 (~64 bytes vs 256)
ES384/ES512ECDSA P-384/P-521384/521-bitFast / FastModern choiceHigher security level
EdDSA / Ed25519EdDSA Curve25519256-bitVery fast / Very fastBEST modern choiceResistant to side-channel attacks; deterministic; RFC 8037
noneNo signatureN/AN/A / N/A🚨 NEVER ACCEPTFamous "alg=none" vulnerability — many libraries had bug accepting unsigned tokens

12 common JWT vulnerabilities

Criticalalg=none acceptance

How: Server accepts JWT with `alg: "none"` header — no signature verification. Attacker forges arbitrary claims.

Mitigation: Reject `alg: none` at parsing layer; whitelist algorithms; never use library defaults

CriticalRS256→HS256 algorithm confusion

How: Server uses public RSA key for HS256 verification. Attacker uses public key as HMAC secret to forge tokens.

Mitigation: Whitelist algorithm per kid; never use a single key for both algorithms; validate alg explicitly

Criticaljku/x5u header spoofing

How: JWT header points to attacker-controlled URL for public key. Server fetches and trusts attacker key.

Mitigation: Whitelist allowed jku/x5u domains; never blindly fetch from header URL

Highkid path traversal

How: `kid` (key ID) used as filesystem path. Attacker uses `../../etc/passwd` or similar.

Mitigation: Treat kid as opaque identifier; lookup in pre-defined map only

Highkid SQL injection

How: `kid` concatenated into SQL query without parameterization.

Mitigation: Always parameterize kid lookups; use prepared statements

HighWeak HMAC secret (brute-forcible)

How: HS256 with secret < 256 bits or dictionary word — brute-forced offline.

Mitigation: Generate cryptographically random 256-bit minimum secrets; use a KMS

HighToken storage in localStorage (XSS)

How: XSS attack steals JWT from localStorage; no HttpOnly protection.

Mitigation: Store in HttpOnly cookies with SameSite=Strict; or use service worker isolation

MediumLong-lived tokens without revocation

How: JWT exp far in future; no way to revoke compromised tokens.

Mitigation: Short exp (5-15 min) + refresh tokens; revocation list (Redis denylist) for compromise

MediumMissing exp/nbf/iat validation

How: Library or custom code skips claim validation — accepts expired tokens.

Mitigation: Use library defaults (jose, jsonwebtoken latest); explicitly validate; clock skew ≤30s

MediumSensitive data in payload

How: PII or secrets in JWT payload — base64 not encryption.

Mitigation: Use JWE (encrypted JWT) for sensitive payloads; or omit and lookup server-side

MediumMissing aud (audience) validation

How: Token issued for service A accepted by service B.

Mitigation: Always validate `aud` claim matches expected audience

MediumCSRF via JWT in cookie without SameSite

How: JWT in cookie automatically sent with cross-site requests.

Mitigation: SameSite=Strict cookies; CSRF token defense-in-depth

Library comparison by language

LanguageLibraryStarsNotes
Node.jsjose6.5KModern, TypeScript-first, supports JWE, ESM
Node.jsjsonwebtoken17KMost popular, larger surface, alg=none deprecated 2025
PythonPyJWT5.2KStandard choice, default verify
Pythonauthlib4.6KOAuth/OIDC integrated
Javajjwt10KSpring ecosystem standard
Javanimbus-jose-jwt650Apache; corporate-grade
Gogolang-jwt/jwt7KForked from dgrijalva/jwt-go after 2021 abandonment
Rustjsonwebtoken1.7KPure Rust, zero unsafe
Rubyruby-jwt3.6KRails standard
PHPfirebase/php-jwt7.6KLaravel ecosystem default
C#/.NETSystem.IdentityModel.Tokens.JwtN/A (Microsoft)Built-in for .NET 6+
Browserjose (web crypto)6.5KSame as Node version, uses Web Crypto API

JWT security best-practice checklist

  1. Whitelist allowed algorithms (don't use library auto-detect)
  2. Reject `alg: none` at parsing
  3. Use Ed25519 or ES256 for new systems; RS256 for OAuth/OIDC compatibility
  4. Generate HS256 secrets via crypto-random 256-bit minimum (use KMS in production)
  5. Store tokens in HttpOnly + Secure + SameSite=Strict cookies
  6. Short access-token exp (5-15 min) + refresh-token rotation
  7. Implement Redis denylist for emergency revocation
  8. Validate `aud` (audience) and `iss` (issuer) claims always
  9. Validate `exp` / `nbf` / `iat` with ≤30 sec clock skew
  10. Whitelist `jku`/`x5u` domains if used; treat `kid` as opaque identifier
  11. Use JWE (RFC 7516) for sensitive payloads, not plain JWS
  12. Log JWT events (issue, refresh, revoke) for forensic analysis
  13. Pin minimum library versions: jose ≥5, jsonwebtoken ≥9, PyJWT ≥2.8

Related Bytepane resources

Sources: RFC 7515 (JWS), RFC 7516 (JWE), RFC 7518 (JWA), RFC 7519 (JWT), RFC 8037 (CFRG/EdDSA), OWASP JWT Cheat Sheet 2025, Tim McLean's 2015 alg=none disclosure, NCC Group JWT security review 2024-2025. Algorithm recommendations align with NIST SP 800-186 (2023, post-quantum considerations) and CFRG IRTF guidance. Always test JWT implementations with a security tool (jwt_tool, JWT Heartbreaker, ZAP JWT add-on) before production deployment.