JWT algorithm confusion: how RS256 tokens get forged as HS256

The token must never choose the key type. Bind each key to one algorithm, and refuse a token whose alg doesn't match the key you're about to use.

Algorithm confusion, also called key confusion, is the other classic flaw from the 2015 JWT library research. A server signs tokens with RS256 and verifies them with its public key. An attacker changes the header to HS256 and signs a forged token with HMAC, using the server's public key as the secret. A library that follows the header then checks the HMAC with that same public key, and the forgery passes.

By TechCompare · Updated

Topic
Algorithm confusion
Key confusion
Category
Pitfalls
Mistakes that let forged tokens through

How this is calculated

The trick works because a public key isn't secret. It's on a JWKS endpoint or in the docs, so the attacker can get the exact PEM text the server holds. Older verify functions took one key argument and used the header's alg to decide how to use it. With RS256 in the header, they ran an RSA check. With HS256, they treated the same bytes as an HMAC secret, and the attacker knows those bytes. Fixes landed in the major libraries years ago, but variants keep appearing: a JWKS that lists keys without an alg, a gateway that passes a key to code that supports both families, or a custom verifier that switches on the header. The defense has three parts. Pin the algorithm in the verify call. Store the algorithm with each key, which a JWK does with its alg member, and refuse a mismatch. Keep symmetric and asymmetric keys in separate code paths. The JWT Decoder follows the same rule: an HS token is only checked with a shared secret, and if you paste something that looks like a PEM or JWK as the secret, it refuses and explains why.

Verdict

If your service only issues RS256 tokens, its verifier should reject everything else, HS256 included. Write a test that signs an HS256 token with your public key as the secret and confirm the API rejects it. That one test covers the whole attack.

More JWT scenarios

Frequently asked questions

Is my app vulnerable to algorithm confusion?
Check how you call verify. If you pass a public key and don't pass an allowed algorithms list, or your library is several years old, test it with an HS256 token signed using the public key's PEM text as the secret.
Does using a JWKS protect me?
It helps when each key has a kty and an alg and your code only uses a key with its own algorithm. A JWKS lookup that grabs a key by kid and then follows the token's header is still open to confusion.
Can this happen with ES256 keys?
The same idea applies to any public key that a library might treat as an HMAC secret. The fix is identical: the key decides the algorithm, never the token.