# Sanitizer output re-parsed into live markup

Filters that re-run substitution or re-emit stored attributes on already-rendered HTML, re-decoding encoded payloads

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

## How it works

A sanitizer or filter assumes its output is final and inert. The assumption breaks when a later stage takes that output and processes it again: re-running pattern substitution over rendered HTML, re-emitting a stored attribute as content, or walking a DOM tree that skips containers. Encoding applied once gets decoded once, and text that was safe as text becomes live markup or attributes. The invariant that fails is "sanitized output is never re-parsed."

## Where it shows up

- A filter that runs `gsub`/replace over `inner_html` or already-rendered nodes rather than only over raw input.
- Prefix checks (`link_pattern_start`) that gate one match while the replace touches all occurrences.
- Redactors that read a `data-*` attribute and re-emit it as link content or HTML.
- Sanitizer post-walk passes (merge text nodes, re-strip) that recurse into `<template>` but not shadow roots, iframes, or other containers the walker cannot descend into.
- Escaping applied to user input but not to filter-generated hrefs or attributes.

## How to review

Trace every stage after the sanitizer. The property to hold: no stage re-parses, re-decodes, or re-substitutes over sanitized output, and every container the sanitizer's walker cannot enter is either scrubbed or rejected. Check whether a stored attribute is decoded on the way out; whether a replace operates on rendered inner HTML; whether a post-walk safety net covers all DOM containers. Confirm encoding is applied at the final output boundary, not only at input.

## Variants seen

- Reference filter re-runs substitution inside rendered anchor inner_html, expanding into attributes and mXSS via SVG/style [E1](https://bugbountylibrary.com/r/h1%3A2257080.md).
- Redactor reuses HTML-encoded `data-original` as raw link content, decoding once into live HTML [E3](https://bugbountylibrary.com/r/h1%3A836649.md).
- Template-expression scrub skips attached shadow roots, so split expressions re-merge and evaluate downstream [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-cg2g-xh64-v4q7.md).

## Why fixes fail

E2 shows a prior template-content fix that did not extend to shadow roots, leaving the same class open in a container the walker still could not reach.

## Impact and severity

Stored XSS in high-traffic rendering paths (wiki, markdown, sanitizer library), enabling script execution in victim sessions. Severity rises when the sink is a shared sanitizer or a stored, cross-user render path; nested anchors and pre-encoded attributes made payloads survive single-pass defenses.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A2257080.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-cg2g-xh64-v4q7.md
- E3: https://bugbountylibrary.com/r/h1%3A836649.md
