Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
Home / Knowledge Base / Insecure JWT Implementation
High CWE-347 A02:2021 Cryptographic Failures

Insecure JWT Implementation

Flawed JWT implementations allow attackers to forge tokens, bypass authentication, and escalate privileges. Learn common JWT pitfalls including algorithm confusion, none algorithm, and weak secrets.

Affects: JavaScriptPythonC#JavaPHPGo

What is an Insecure JWT Implementation?

JSON Web Tokens (JWTs) are widely used for stateless authentication. A JWT consists of three base64url-encoded parts: header, payload, and signature. The signature ensures the token has not been tampered with. When JWT libraries or application code are misconfigured, attackers can forge arbitrary tokens and impersonate any user — including administrators.

The most critical vulnerabilities include: accepting the none algorithm (no signature required), algorithm confusion attacks (swapping RS256 for HS256 using the public key as secret), using weak or default HMAC secrets, and trusting the kid (Key ID) header for key selection without validation.

How exploitation works

The “none” algorithm attack

A valid JWT header specifies "alg": "RS256". An attacker changes it to "alg": "none", removes the signature, and modifies the payload (e.g., "role": "admin"). Libraries that accept none verify the token as valid with no signature check:

# Original token (simplified)
header: {"alg":"RS256"} | payload: {"sub":"1","role":"user"} | <signature>

# Forged token — no signature, role escalated
header: {"alg":"none"} | payload: {"sub":"1","role":"admin"} |

Algorithm confusion (RS256 → HS256)

When a server uses RS256, the public key is typically discoverable. If the library accepts both RS256 and HS256, an attacker signs a token with HS256 using the public key as the HMAC secret — the server then verifies the HMAC signature using that same public key.

Vulnerable code examples

Node.js — accepting any algorithm

// VULNERABLE: Allows 'none' algorithm; attacker can forge unsigned tokens
const decoded = jwt.verify(token, publicKey); // No algorithms restriction

Python — no verification

# VULNERABLE: decode() without verify=True skips signature validation entirely
import jwt
payload = jwt.decode(token, options={"verify_signature": False})

Secure code examples

Node.js — explicit algorithm allowlist

// SECURE: Explicitly restrict to expected algorithm; reject 'none'
const decoded = jwt.verify(token, publicKey, {
  algorithms: ['RS256'],  // Allowlist — 'none' and 'HS256' are rejected
  issuer: 'https://auth.example.com',
  audience: 'my-api',
});

C# / ASP.NET Core — strict JWT validation

// SECURE: Validate algorithm, issuer, audience, and expiry
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new RsaSecurityKey(rsaPublicKey),
            ValidAlgorithms = new[] { SecurityAlgorithms.RsaSha256 }, // Allowlist
            ValidateIssuer = true,
            ValidIssuer = "https://auth.example.com",
            ValidateAudience = true,
            ValidAudience = "my-api",
            ValidateLifetime = true,
        };
    });

What Offensive360 detects

  • none algorithm acceptance — JWT verification calls that do not restrict the algorithms parameter
  • Missing signature verificationdecode() calls with signature verification disabled
  • Weak HMAC secrets — Secrets that are short, default values, or predictable strings used with HS256/HS512
  • kid header injection — Key ID values used in file paths or database queries without sanitization (can lead to path traversal or SQL injection)
  • Missing claims validation — Absence of iss, aud, or exp claim verification

Remediation guidance

  1. Explicitly specify allowed algorithms — Never rely on the algorithm declared in the token header. Hard-code the expected algorithm in verification calls.

  2. Never disable signature verification — Even for debugging. Use short-expiry test tokens with real signatures.

  3. Use strong, randomly-generated secrets — For HS256, use at least 256 bits of cryptographically random data. For production, prefer RS256 or ES256 asymmetric signing.

  4. Validate all standard claims — Always check exp (expiry), iss (issuer), and aud (audience) in verification logic.

  5. Rotate secrets and key pairs — Implement key rotation with short-lived tokens to limit the blast radius of a compromised key.

References

By Offensive360 Security Research Reviewed: March 2026

Detect Insecure JWT Implementation automatically

Run Offensive360 SAST on your codebase to find this and 100+ other vulnerabilities.