# Unvalidated URL scheme to OS launch

Server- or page-controlled URLs reaching openUrl, shell.openExternal, or window.open without an http/https allowlist

_Area: Web injection and code execution. Seen in 4 disclosed reports; 2 confirmed bounties: $560 and $1,000; latest 2021-04-15. Updated 2026-11-02._

## How it works

A link handler trusts the URL it is given and hands it to the OS or embedded browser without checking the scheme. The assumption that breaks: that a link is just a link. The OS dispatches `file:`, `javascript:`, custom, and helper-app schemes to native handlers, and a WebView may run `javascript:` in the top document. Whoever controls the page (a malicious server, ad content, an open redirect) controls the scheme, so a navigation becomes code execution or cross-origin script.

## Where it shows up

- Desktop clients calling `QDesktopServices::openUrl()` or Electron `shell.openExternal()` on server- or page-supplied URLs [E1](https://bugbountylibrary.com/r/h1%3A1078002.md)[E4](https://bugbountylibrary.com/r/h1%3A301458.md)
- Embedded login WebViews rendering a server-controlled page [E1](https://bugbountylibrary.com/r/h1%3A1078002.md)
- Custom URL scheme handlers whose allowlist is a domain that itself passes through an open redirect [E3](https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-open-sesame-escalating-open-redirect-to-rce-with-electron-code-review.md)
- Android WebViews with `setSupportMultipleWindows` left default/false while rendering third-party or ad content [E2](https://bugbountylibrary.com/r/h1%3A906433.md)
- `nodeIntegration:true` with `require` re-exposed via preload, widening any scheme-handler bug to RCE [E3](https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-open-sesame-escalating-open-redirect-to-rce-with-electron-code-review.md)
- `file://` reaching an external launcher, especially remote NFS/SMB paths [E4](https://bugbountylibrary.com/r/h1%3A301458.md)

## How to review

Find every call site that passes a URL to an OS launcher or WebView navigation. The invariant: the scheme must be checked against an explicit allowlist (http/https only) *after* all redirects and normalization, and the check must not rely on a URL that can be redirected. For WebViews, confirm `setSupportMultipleWindows` is true when untrusted content is rendered, and that `javascript:` cannot reach the top document. For Electron, confirm `nodeIntegration` is off and preload does not re-expose `require`. Treat any domain-based allowlist as unsafe if that domain has an open redirect.

## How finders spotted it

- Noticed the Add Account flow opens the server login site in a native WebView and links route through `QDesktopServices::openUrl()`, so a malicious server controls the schemes [E1](https://bugbountylibrary.com/r/h1%3A1078002.md)
- Pentested many Android browsers, traced the cause to WebView with `setSupportMultipleWindows` false, then checked which apps used that config [E2](https://bugbountylibrary.com/r/h1%3A906433.md)
- Decompiled asar, grepped `globalShortcut` to recover a hidden DevTools menu, read the custom scheme handler and saw its whitelist relied on a redirectable URL [E3](https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-open-sesame-escalating-open-redirect-to-rce-with-electron-code-review.md)
- Code-read the external-links handler and saw `shell.openExternal` received unvalidated URLs, reasoning `file://` opens native apps [E4](https://bugbountylibrary.com/r/h1%3A301458.md)

## Variants seen

- Server-controlled login page injecting arbitrary schemes into OS handlers [E1](https://bugbountylibrary.com/r/h1%3A1078002.md)
- `javascript:` URL via `window.open` from a cross-origin iframe executing in the top origin [E2](https://bugbountylibrary.com/r/h1%3A906433.md)
- Open redirect chained to a custom scheme handler with `nodeIntegration` [E3](https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-open-sesame-escalating-open-redirect-to-rce-with-electron-code-review.md)
- `file://` to a remote executable through `shell.openExternal` [E4](https://bugbountylibrary.com/r/h1%3A301458.md)

## Impact and severity

RCE on the victim host in three cases [E1](https://bugbountylibrary.com/r/h1%3A1078002.md)[E3](https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-open-sesame-escalating-open-redirect-to-rce-with-electron-code-review.md)[E4](https://bugbountylibrary.com/r/h1%3A301458.md); UXSS in the fourth [E2](https://bugbountylibrary.com/r/h1%3A906433.md). Impact rose when combined with another weakness: a malicious server [E1](https://bugbountylibrary.com/r/h1%3A1078002.md), `nodeIntegration` plus open redirect [E3](https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-open-sesame-escalating-open-redirect-to-rce-with-electron-code-review.md). E4's escalation was none on its own—the `file://` launch was the whole bug. Bounties were modest (median 780) but severity was high because a link click reached native code execution.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A1078002.md
- E2: https://bugbountylibrary.com/r/h1%3A906433.md
- E3: https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-open-sesame-escalating-open-redirect-to-rce-with-electron-code-review.md
- E4: https://bugbountylibrary.com/r/h1%3A301458.md
