# javascript URI in navigation sink

User URL reaches iframe src, window.open or link handler without post-parse scheme allowlist

_Area: Web injection and code execution. Seen in 2 disclosed reports; 2 confirmed bounties: $560 and $12,000; latest 2020-09-24. Updated 2026-10-24._

## How it works
A URL from an untrusted source is handed to a navigation sink (iframe src, window.open, link click handler, redirect endpoint) and the code trusts the sink to reject dangerous schemes. The sink does not parse the URL the way the developer assumes: it may treat a `javascript:` URL as an ordinary navigation, or the app's own filter may only check the string before parsing. When the scheme is not checked after parsing, the `javascript:` payload executes in the origin of the document that navigated, not the origin that supplied the URL.

## Where it shows up
- iframe `src`, `window.open`, `location` assignment, or anchor handlers fed by user or third-party content
- Redirect/forwarder endpoints (e.g. `/external`) that wrap arbitrary user URLs
- Android WebViews rendering third-party or ad content with `setSupportMultipleWindows` left at default/false [E1](https://bugbountylibrary.com/r/h1%3A906433.md)
- Same-domain filters that can be bypassed with protocol-relative `//` or alternate schemes [E2](https://bugbountylibrary.com/r/blog%3Asamcurry-net-the-12000-intersection-between-clickjacking-xss-and-denial-of-service.md)
- CSP present but the sink is a `javascript:` URL in iframe src [E3](https://bugbountylibrary.com/r/blog%3Aweizman-github-io-2020-09-02-csp-vuln.md)

## How to review
Trace every user-controlled URL to its sink. The invariant: the scheme must be extracted by a real URL parser and checked against an explicit allowlist (`https`, `http`) after parsing, before the value reaches the sink. Reject anything that fails to parse. For WebViews, confirm `setSupportMultipleWindows(true)` or equivalent when rendering untrusted content [E1](https://bugbountylibrary.com/r/h1%3A906433.md). For redirect endpoints, confirm the scheme is validated server-side, not just client-side [E2](https://bugbountylibrary.com/r/blog%3Asamcurry-net-the-12000-intersection-between-clickjacking-xss-and-denial-of-service.md). Do not rely on CSP alone to stop `javascript:` execution in navigation sinks [E3](https://bugbountylibrary.com/r/blog%3Aweizman-github-io-2020-09-02-csp-vuln.md).

## Variants seen
- Cross-origin iframe calling `window.open` with a `javascript:` URL, executing in the top document via WebView behavior [E1](https://bugbountylibrary.com/r/h1%3A906433.md)
- Chat link handler plus `/external` redirect forwarding `javascript:` URIs without scheme validation [E2](https://bugbountylibrary.com/r/blog%3Asamcurry-net-the-12000-intersection-between-clickjacking-xss-and-denial-of-service.md)
- Browser CSP not applied to `javascript:` URL used as iframe src, bypassing `script-src` [E3](https://bugbountylibrary.com/r/blog%3Aweizman-github-io-2020-09-02-csp-vuln.md)

## Impact and severity
Led to UXSS in a major app [E1](https://bugbountylibrary.com/r/h1%3A906433.md), stored XSS in chat with clickjacking and client DoS [E2](https://bugbountylibrary.com/r/blog%3Asamcurry-net-the-12000-intersection-between-clickjacking-xss-and-denial-of-service.md), and full CSP bypass across platforms [E3](https://bugbountylibrary.com/r/blog%3Aweizman-github-io-2020-09-02-csp-vuln.md). Severity is high because execution lands in the trusted origin, defeating origin and CSP boundaries. Worse when the sink renders third-party/ad content or when a redirect endpoint is same-domain trusted.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A906433.md
- E2: https://bugbountylibrary.com/r/blog%3Asamcurry-net-the-12000-intersection-between-clickjacking-xss-and-denial-of-service.md
- E3: https://bugbountylibrary.com/r/blog%3Aweizman-github-io-2020-09-02-csp-vuln.md
