# XSS via base tag or service worker

Markup injection that plants a base tag or registers a service worker, hijacking script loads on the origin

_Area: Web injection and code execution. Seen in 3 disclosed reports; 2 confirmed bounties: $3,134 and $16,000; latest 2024-08-01. Updated 2026-10-24._

## How it works

XSS normally needs script execution in the page. These cases get it indirectly: injected markup changes *where* the browser loads scripts from, or makes the origin serve attacker bytes as script. A `<base href>` tag retargets every relative script URL to an attacker domain, so a page that blocks inline script but allows the tag still runs attacker code. Separately, if an endpoint on the origin returns attacker-controlled bytes with a JavaScript content type, a service worker can be registered from it, giving persistent interception of the origin's fetches. The broken assumption: sanitizers and CSP treat markup injection as harmless if no script tag survives, and treat same-origin fetch endpoints as trusted because they are same-origin.

## Where it shows up

- Markdown/HTML renderers whose sanitizer allows `<base>`, `<link>`, or similar URL-affecting tags while blocking `<script>`.
- Fixes that patched one injection vector (e.g. an emoji path) but left the underlying filter injectable.
- Proxy or debugger endpoints that fetch an attacker-supplied URL and return it with a JS MIME type.
- Download endpoints serving attacker-uploaded files with preserved MIME type despite `Content-Disposition: attachment`.
- Browser logic that parses a response body as a manifest or script when it previously ignored it.

## How to review

Check the invariant: no attacker-influenced markup may alter the document base URL or script source resolution, and no origin endpoint may return attacker bytes with an executable content type. Concretely: does the sanitizer's allowlist exclude `<base>` and other URL-retargeting tags, and is that enforced at the sink rather than per-vector? Does CSP include `base-uri`? Do proxy/fetch endpoints restrict target URLs and force a non-executable content type? Does the manifest/script fetch path honor `Content-Disposition: attachment`? For each fix, ask whether it closes the primitive or only one tag.

## Variants seen

- `<base>` tag injected through Markdown syntax highlighting, bypassing CSP by retargeting relative scripts [E2](https://bugbountylibrary.com/r/h1%3A1481207.md).
- Service worker registered from an attacker-uploaded manifest parsed by the browser's payment API [E1](https://bugbountylibrary.com/r/blog%3Ablog-slonser-info-posts-cve-2023-5480.md).
- Service worker registered through a debugger proxy that serves attacker JS from the victim origin, intercepting an OAuth redirect [E3](https://bugbountylibrary.com/r/blog%3Andevtk-github-io-writeups-2024-08-01-projectidx.md).

## Why fixes fail

E2's earlier fix patched only the emoji vector, leaving the HTML injection primitive intact; other tags such as `<base>` still passed [E2](https://bugbountylibrary.com/r/h1%3A1481207.md).

## Impact and severity

Stored XSS on a major origin despite CSP [E2](https://bugbountylibrary.com/r/h1%3A1481207.md); account takeover via leaked HttpOnly token in a redirect URL [E3](https://bugbountylibrary.com/r/blog%3Andevtk-github-io-writeups-2024-08-01-projectidx.md); origin XSS from uploaded files [E1](https://bugbountylibrary.com/r/blog%3Ablog-slonser-info-posts-cve-2023-5480.md). Severity is high because the injection survives CSP and can persist via service workers.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Ablog-slonser-info-posts-cve-2023-5480.md
- E2: https://bugbountylibrary.com/r/h1%3A1481207.md
- E3: https://bugbountylibrary.com/r/blog%3Andevtk-github-io-writeups-2024-08-01-projectidx.md
