JWT algorithm confusion to account takeover
An API verifies RS256 JWTs but will also accept HS256. Because the RSA public key is, by definition, public, an attacker re-signs a forged token with HMAC-SHA256 using that public key as the shared secret — the server validates it and trusts whatever claims it carries.
Scenario
A single-page app authenticates to a JSON API with a bearer JWT. The token is signed RS256, and the server library is left on its default of accepting any algorithm named in the token header. The public key is reachable at a standard JWKS endpoint. That one misconfiguration turns a public key into a forging key.
- 1
Discovery
Capture a valid token and read its header
Log in as a low-privilege user and grab the issued JWT from the Authorization header or a cookie. Base64url-decode the header and confirm "alg":"RS256" and a key id. Asymmetric signing is the precondition for the whole attack, so establish it before going further.
DetectionMany short-lived sessions or token requests from one client, and tokens being read client-side, are weak signals on their own; pair them with the forgery signals below.
MitigationTreat the token as sensitive: short expiry, HttpOnly/SameSite cookies where possible, and no secrets in claims.
- 2
Credential access
Obtain the RSA public key the server verifies with
Fetch the public key from the standard JWKS / well-known endpoint, a /publickey route, or recover it from two legitimately signed tokens. Convert the JWK to PEM. This key is meant to be public — the flaw is that the server will treat it as an HMAC secret in the next step.
DetectionNormal retrieval of a public key is not suspicious by itself; alert instead on the mismatch it enables — see the verification signals below.
MitigationPublishing the public key is expected and fine; the real fix is pinning the algorithm (next stage), not hiding the key.
- 3
Defense evasion
Forge an HS256 token the server accepts
Change the header to "alg":"HS256", edit the payload (for example raise the role or change the subject to another user), and compute the HMAC-SHA256 signature using the exact public-key bytes (PEM) as the secret. A server that honours the header's algorithm verifies HS256 with that same public value and accepts the token as genuine.
DetectionThe strongest signal is a token whose algorithm changed between issue and use (RS256 issued, HS256 presented), or a verified token whose claims never corresponded to any real login. Log the alg actually used to verify.
MitigationPin the accepted algorithm server-side to exactly the one you issue (an allow-list, never the token's own header); keep verification keys for symmetric and asymmetric algorithms strictly separate.
- 4
Account takeover
Act as a privileged or arbitrary user
Send the forged token to privileged API routes. With the subject or role claim under the attacker's control, the session is whatever the claims say — an administrator, or any chosen user — without ever knowing a password.
DetectionPrivileged API calls from a session that never completed a matching authentication, abrupt role changes within one token lineage, and access to accounts with no corresponding login event.
MitigationEnforce authorization server-side against a trusted store rather than trusting token claims alone; bind sessions to additional factors and re-check sensitive actions.
Key takeaways
- Algorithm confusion works because the server lets the token's own header choose the verification algorithm — the fix is to pin the algorithm on the server, not in the token.
- A public key is safe to publish but must never double as an HMAC secret; symmetric and asymmetric verification paths have to use separate, typed keys.
- Signature validity is not authorization: always check what a verified token is allowed to do against a trusted server-side source.