# SVG and entity-encoded sanitizer bypass

Sanitizer output that re-parses as markup or script in a different context (namespace, entity, JS string)

_Area: Web injection and code execution. Seen in 3 disclosed reports; one confirmed bounty: $10,000; latest 2026-10-27. Updated 2026-11-02._

## How it works
A sanitizer judges input in one parsing context, but the browser re-parses the same bytes in another, so a payload it approved executes. The evidence shows several distinct divergences: XML namespace switching and `<animate>`/`animateTransform` attribute mutation that change an element's meaning after inspection, plus `xml-stylesheet` data URLs, Firefox `Link`-header XSLT loading, and Safari importing images as SVG via `<use>` [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md); entity-encoded tags placed inside a delimiter the downstream parser still processes [E2](https://bugbountylibrary.com/r/blog%3Asaajan-bhujel-cyou-blog-web-2022-10-16-how-i-got-10000-from-github-for-bypassing-filtration-of-html-tags.md); and HTML-entity encoding applied to a value that lands inside a JavaScript string literal in an HTML attribute, where the browser decodes entities before JS parsing [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md).

## Where it shows up
- SVG sanitizers that walk elements without tracking `xmlns`/namespace switches, or match tags case-sensitively via `querySelectorAll` [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md)
- `<animate>`/`<animateTransform>` whose `href`/attribute values mutate after sanitization [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md)
- `xml-stylesheet` processing instructions with data URLs; Firefox loading XSLT/CSS from a `Link` response header [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md)
- Safari importing image files as SVG via `<use>` [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md)
- Markdown/math renderers (MathJax) where backslash-escaped or entity-encoded tags sit inside `{}` delimiters [E2](https://bugbountylibrary.com/r/blog%3Asaajan-bhujel-cyou-blog-web-2022-10-16-how-i-got-10000-from-github-for-bypassing-filtration-of-html-tags.md)
- Template values interpolated into inline `onclick`/JS string literals inside HTML attributes [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md)
- Sanitizers emitting HTML numeric character references for values that reach a JS-string-in-attribute sink [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md)

## How to review
Identify every sink and the exact parsing context it imposes (XML namespace, HTML attribute, JS string, CSS, URL). The invariant: the sanitizer must reason in the same context the browser will use, and its output must not re-parse into markup or script. Concretely: does it normalize namespaces and case before matching? Does it re-check attributes after animate mutation? Does it treat entity-encoded text as inert only where the parser truly treats it as text? For attribute-embedded JS, HTML-entity encoding is not sufficient — the value must be JS-string-escaped (or the handler removed).

## How finders spotted it
- Started from a tip that Firefox loads external CSS via the `Link` header, hypothesized data URLs would work, then extended to XSLT; separately tested namespace switching, `querySelectorAll` case sensitivity, animate mutation, and Safari `<use>` image import [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md)
- Read the vendor's MathJax announcement, checked known MathJax XSS CVEs, found them patched, then fuzzed delimiter/backslash/entity encodings and iterated after each fix by moving the payload position [E2](https://bugbountylibrary.com/r/blog%3Asaajan-bhujel-cyou-blog-web-2022-10-16-how-i-got-10000-from-github-for-bypassing-filtration-of-html-tags.md)
- Code review of a comment template spotted `{COMMENT.post_name}` inside an inline `onclick` JS string and recognized entity decoding happens before JS parsing [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md)

## Variants seen
- Namespace confusion, animate href mutation, data-URL XSLT, Link-header XSLT, Safari GIF-as-SVG import [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md)
- Backslash-prefixed and entity-encoded tags inside MathJax braces [E2](https://bugbountylibrary.com/r/blog%3Asaajan-bhujel-cyou-blog-web-2022-10-16-how-i-got-10000-from-github-for-bypassing-filtration-of-html-tags.md)
- Entity-encoded name breaking out of an inline JS string, split across two profile fields [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md)

## Why fixes fail
GitHub patched known MathJax CVEs, yet the sanitizer still missed entity-encoded tags inside braces; each fix was bypassed by relocating the payload [E2](https://bugbountylibrary.com/r/blog%3Asaajan-bhujel-cyou-blog-web-2022-10-16-how-i-got-10000-from-github-for-bypassing-filtration-of-html-tags.md).

## Impact and severity
XSS in victim browsers: six of eight SVG sanitizers bypassed [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md); GitHub paid $10,000, reaching full-page CSS control and a credential-phishing overlay though not script execution [E2](https://bugbountylibrary.com/r/blog%3Asaajan-bhujel-cyou-blog-web-2022-10-16-how-i-got-10000-from-github-for-bypassing-filtration-of-html-tags.md); stored XSS with cookie exfiltration and admin session hijack yielding privilege escalation [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md). Impact rose with reach (any visitor, admin) and chaining with browser quirks [E1](https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md).

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-scalable-vector-grief.md
- E2: https://bugbountylibrary.com/r/blog%3Asaajan-bhujel-cyou-blog-web-2022-10-16-how-i-got-10000-from-github-for-bypassing-filtration-of-html-tags.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-w2w5-w2pw-r929.md
