Safeguard
Vulnerability Guides

JWT Security Vulnerabilities and How to Avoid Them

JSON Web Tokens are only as safe as how you verify them. The alg:none trick, RS256-to-HS256 confusion, and weak secrets have all led to full auth bypass.

Daniel Osei
Security Researcher
5 min read

JSON Web Tokens (JWTs) are compact, signed claims used everywhere for authentication and authorization. Their security depends entirely on the verification step, and that is exactly where implementations go wrong. The recurring failures are accepting the none algorithm (an unsigned token), confusing an asymmetric algorithm with a symmetric one so the public key becomes the signing secret, and signing with guessable secrets that fall to offline brute force. Each of these turns a token into something an attacker can forge, which means full authentication bypass.

These are not theoretical. In 2015, security researcher Tim McLean documented critical vulnerabilities across multiple JWT libraries, including the alg:none bypass and the RS256-to-HS256 confusion attack. Years later the same class persists: CVE-2022-23529 was a vulnerability in the widely used Node.js jsonwebtoken library (versions through 8.5.1) that, under specific conditions, allowed attackers to influence verification through a crafted secretOrPublicKey. When your whole auth model rests on a signature check, a flaw in that check is a skeleton key.

How JWT Attacks Work

A JWT has three Base64URL parts: a header (algorithm and type), a payload (claims like sub, role, exp), and a signature. Verification must recompute the signature over the header and payload using a trusted key and reject anything that does not match. The attacks all subvert that step.

alg:none. The JWT spec defines an "unsecured" mode where alg is none and there is no signature. If a library honors it, an attacker strips the signature, sets "alg":"none", edits the payload to "role":"admin", and is trusted. The fix is to never accept none for authentication tokens.

Algorithm confusion (RS256 to HS256). With RS256 the server verifies using an RSA public key; with HS256 it verifies using a symmetric secret. If verification code picks the algorithm from the token's own header, an attacker changes RS256 to HS256 and signs the forged token using the server's public key as the HMAC secret. The public key is, by definition, public — so the forgery verifies. The fix is to pin the expected algorithm server-side and never let the token choose.

Weak secrets. HS256 tokens signed with a short or dictionary secret can be cracked offline; once the secret is known, any token can be forged. Use long, random secrets and rotate them.

Vulnerable vs. Fixed

The dangerous pattern is trusting the token's header to decide how to verify.

// VULNERABLE: algorithm comes from the attacker-controlled token header
const jwt = require("jsonwebtoken");

function verifyToken(token, key) {
  // no algorithms option -> library may accept none / HS256 with public key
  return jwt.verify(token, key);
}
// FIXED: pin the algorithm(s), require expiry, validate audience/issuer
const jwt = require("jsonwebtoken");

function verifyToken(token) {
  return jwt.verify(token, PUBLIC_KEY, {
    algorithms: ["RS256"],       // server decides, not the token
    issuer: "https://auth.example.com",
    audience: "api://example",
    maxAge: "15m",               // reject stale tokens
  });
}

Pinning algorithms: ["RS256"] defeats both alg:none and the HS256 confusion attack in one line, because a token claiming any other algorithm is rejected before its signature is even checked.

Prevention Checklist

  • Pin the expected algorithm in every verify call; never derive it from the token header.
  • Reject alg:none for anything used to authenticate or authorize.
  • Use strong, random secrets for HMAC (256 bits of entropy) and rotate signing keys with a key-ID (kid) strategy.
  • Always validate exp, iss, and aud, and keep access-token lifetimes short.
  • Do not put secrets or trust-sensitive PII in the payload — it is only Base64, not encrypted.
  • Maintain revocation via short lifetimes plus refresh tokens or a deny-list for critical logout/ban flows.
  • Keep JWT libraries patched, since verification bugs recur across versions.

How Safeguard Detects JWT Vulnerabilities

JWT risk spans your dependencies and your runtime behavior, so Safeguard covers both. Software composition analysis identifies the JWT libraries in your project and flags versions with known verification CVEs — including the jsonwebtoken advisories — so you upgrade before an attacker leans on a library bug. In parallel, the dynamic testing engine submits tampered tokens against live endpoints — alg:none, swapped algorithms, expired tokens — and reports which forgeries the server actually accepts.

Findings are triaged into a prioritized, plain-English explanation with the algorithm-pinning fix, and automated remediation can open the corresponding pull request. You can enforce all of this pre-merge with the Safeguard CLI in CI. Teams migrating from a dependency-only scanner may find our Snyk comparison useful for seeing where runtime token testing adds coverage.

Frequently Asked Questions

Is a JWT encrypted? No. A standard signed JWT (JWS) is only signed, not encrypted — the header and payload are Base64URL-encoded and readable by anyone who holds the token. If you need confidentiality of claims, use JWE (encrypted tokens) or simply keep sensitive data out of the token.

Why is algorithm confusion so dangerous? Because the "secret" it exploits is public. When code lets the token pick HS256 and the server verifies with what it thinks is a key, an attacker signs a forged token using the server's public RSA key as the HMAC secret. Pinning the algorithm server-side removes the choice and the attack.

How do I revoke a JWT before it expires? Stateless JWTs cannot be un-issued, so use short access-token lifetimes with rotating refresh tokens, and maintain a server-side deny-list (keyed by token ID) for high-impact events like logout, password change, or account ban.


Want to know which tampered tokens your API would accept today? Start free or read the authentication-testing guide in the Safeguard docs.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.