Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type JWT Attacks
Difficulty Expert
Objective Derive the server's RSA public key from two signed tokens, then use it as an HMAC secret to forge a valid HS256 token as administrator and delete carlos

JWT Authentication Bypass via Algorithm Confusion with No Exposed Key

I logged in as wiener:peter and decoded the session JWT:

Screenshot

Header: alg: RS256. No /jwks.json endpoint exposing the public key — the key has to be derived.

In RSA, the signature S = M^d mod n ties the message, private exponent, and public modulus together mathematically. Given two signed messages and their signatures from the same private key, there are relationships that allow recovering n — the public modulus, which is the only component needed for the algorithm confusion attack. Not having a JWKS endpoint doesn't make the key unrecoverable: any application that signs multiple JWTs with the same key is potentially vulnerable to this recovery technique.

The tool portswigger/sig2n automates this. Given two JWTs signed with the same RSA private key, it derives candidate n values, reconstructs candidate public keys, and outputs tampered JWTs already signed with HS256 using the derived key — so you can test immediately whether the derivation was correct.

I logged in a second time to get a fresh token with a different payload (log out and back in ensures exp or iat differ — two tokens with identical payloads produce the same signature and give the algorithm nothing new to work with), then ran the tool with both:

docker run --rm -it portswigger/sig2n \
  'eyJraWQiOiI1YzM3NTc1Yi1hNjIwLTRmMDMtOTM4Ni02Zjg2MzMyZTRiNDAiLCJhbGciOiJSUzI1NiJ9...' \
  'eyJraWQiOiI1YzM3NTc1Yi1hNjIwLTRmMDMtOTM4Ni02Zjg2MzMyZTRiNDAiLCJhbGciOiJSUzI1NiJ9...'
Screenshot

I pasted the tampered JWT from the output as the session cookie to verify the derived key:

Screenshot

200 OK with wiener's account loaded — the derived key matched. From here the attack is identical to the previous lab: import the base64-encoded X.509 public key as a symmetric key in Burp's JWT Editor, change sub to administrator, sign with HS256. The difference between this lab and the previous one is only in how you get the key.

Screenshot
Screenshot

Signed the forged token and pasted it into the browser:

Screenshot

Admin panel loaded. Deleted carlos:

Screenshot

Lab solved and section finished

Resources