JSON Web Tokens are everywhere in modern authentication, and algorithm confusion is one of the few JWT bugs that turns a read-only foothold into full account takeover. The attack is simple once you see it: the token tells the server how to verify the token. If the server believes it, an attacker can pick an algorithm the server never intended to accept.
What is JWT algorithm confusion?
Algorithm confusion is an attack where a signed JSON Web Token is modified so its alg header
names a different signing algorithm than the server intended, and the server verifies it anyway
using the wrong key. In the common case an attacker changes RS256 to HS256, then signs the
forged token with the server’s own public key. Because the server passes that same public key
into an HMAC verification routine, the signature checks out and the attacker can set any claim
they like, including an administrator role. The bug is not in the cryptography. It is in
letting untrusted input choose which verification path runs.
Why RS256 and HS256 make this possible
The two algorithms have fundamentally different key models, and that mismatch is the whole bug.
| RS256 | HS256 | |
|---|---|---|
| Type | Asymmetric | Symmetric |
| Signs with | Private key | Shared secret |
| Verifies with | Public key | The same shared secret |
| Key is secret? | Only the private key | Yes, always |
Under RS256 the public key is meant to be public. Publishing it is the entire point, since anyone should be able to verify a token without being able to mint one. Under HS256 the verification key and the signing key are the same value, so anything that can verify can also sign.
Now consider a library call like verify(token, key) where key holds the RSA public key and
the algorithm is read from the token itself. Send a token with "alg": "HS256" and the library
treats that public key as an HMAC secret. The attacker knows the public key. So the attacker
can produce a valid signature.
The dangerous ingredient is trusting the alg header. A verifier that accepts whatever
algorithm the token names is deciding security policy based on attacker-controlled input.
The attack, step by step
1. Obtain the public key
Sometimes the key is simply published, at /jwks.json, /.well-known/jwks.json, or in API
documentation. When it is not exposed directly, it can often be recovered from two tokens
signed by the same private key, which is enough to solve for the RSA modulus.
2. Change the algorithm and the claims
Decode the token, set the header to {"alg": "HS256", "typ": "JWT"}, and edit the payload to
claim whatever the application checks, typically something like "role": "admin" or
"isAdmin": true.
3. Sign with the public key as the HMAC secret
This is the step that trips people up. The HMAC secret must be the exact byte sequence the server passes to its verify call, usually the PEM-encoded public key including its header and footer lines and its trailing newline. A single byte of difference produces a different signature and the forgery fails, which is why this attack is often abandoned one step before it would