July 30, 2026

JWT Algorithm Confusion: The Attack That Exploits Trusting the Token's Own Header

JWT algorithm confusion happens when a server accepts whatever signing algorithm a token's own header declares instead of enforcing one server-side — an attacker can then take an RS256 token's public key (which is meant to be public) and use it as an HS256 secret to forge a validly-signed token. Fixing it means explicitly specifying which algorithm your server accepts, never reading that decision from the token itself.

JWT Decoder showing a token's header field alg: HS256 alongside its decoded payload claims, illustrating the algorithm field an attacker would target in an algorithm confusion attack

The setup: RS256 vs. HS256

RS256 is an asymmetric algorithm — the server signs tokens with a private key and verifies them with a corresponding public key, which is often distributed openly (it has to be, for other systems to verify tokens). HS256 is symmetric — the same secret key is used both to sign and to verify a token, and that secret must stay confidential.

How the attack works

If a server is configured to accept RS256 tokens but doesn't strictly enforce which algorithm a submitted token actually uses, an attacker can craft a new token with its header alg field changed from RS256 to HS256, then sign it using the server's own RS256 public key as if it were an HS256 secret. Since the public key is, by design, not secret, the attacker can compute a valid HS256 signature with it. A vulnerable server, trusting the token's self-declared alg field, verifies the forged token using the public key as an HMAC secret — and the forged signature checks out, letting the attacker forge tokens for any user.

The fix: never let the token choose its own verification method

  • Explicitly specify which algorithm(s) your server accepts when verifying — never read the algorithm from the incoming token's own header and use that to decide how to verify it
  • Use separate, purpose-specific keys for RS256 and HS256 if you must support both — never let the same key material serve as both a public verification key and a symmetric secret
  • Reject tokens with alg: none outright — some libraries historically accepted this as "unsigned, trust it anyway," which is its own well-known vulnerability class

This is also a good reminder of what a JWT decoder is for and isn't for: reading and debugging a token's header and payload client-side is safe and useful, but it never substitutes for correct signature verification on the server, which has to enforce its own algorithm expectations rather than trusting whatever the token claims about itself.

Want to try this yourself?

Open JWT Decoder