Follow-up to #176, which switched four rules from element.remove() to scrubbing their data carriers in place so framework-tracked nodes (React/Vue/Svelte/Astro/htmx) stay attached. That change opened two narrow coverage gaps in meta-injection-strip and noscript-strip:
Gap 1 — meta-injection-strip: in-place content= updates aren't re-scanned
SubtreeWatcher's shared OBSERVED_ATTRIBUTES list (extension/src/lib/subtree-watcher.ts:50) only includes id and class, because that's all the selector-token dispatcher keys on. If a framework or page script later writes a new poisoned value to content= on a meta node we previously blanked, the new value is visible to agents until the next route change or subtree addition re-triggers a scan.
Pre-#176 this was masked because the meta was detached — any framework write landed on a node nobody was reading.
Gap 2 — noscript-strip: children re-rendered into a kept <noscript> aren't recognized
stripNoscript (extension/src/rules/noscript-strip.ts:46) is downward-only: it matches when the watcher subtree is a <noscript> or contains one. When new children are added into a <noscript> we already blanked, the watcher fires on the new children, but stripNoscript walks downward — it doesn't recognize that the added subtree's ancestor is a noscript.
Pre-#176 this was masked because the noscript was gone, so any new content had to bring its own <noscript> wrapper. Real-world likelihood is very low: frameworks essentially never re-render noscript children at runtime.
Proposed fix
- Extend
OBSERVED_ATTRIBUTES (or expose a per-subscriber attributeFilter) so content mutations on meta elements reach meta-injection-strip, and have the rule subscribe with observeAttributes: true.
- Add an upward
closest(\"noscript\") check inside stripNoscript so a subtree added under a kept noscript is recognized as noscript content.
Out of scope
- Broader
html-comment-strip recoverage — tracked separately.
INJECTION_PATTERNS audit on attribute-targeted rules — tracked separately.
Follow-up to #176, which switched four rules from
element.remove()to scrubbing their data carriers in place so framework-tracked nodes (React/Vue/Svelte/Astro/htmx) stay attached. That change opened two narrow coverage gaps inmeta-injection-stripandnoscript-strip:Gap 1 —
meta-injection-strip: in-placecontent=updates aren't re-scannedSubtreeWatcher's sharedOBSERVED_ATTRIBUTESlist (extension/src/lib/subtree-watcher.ts:50) only includesidandclass, because that's all the selector-token dispatcher keys on. If a framework or page script later writes a new poisoned value tocontent=on a meta node we previously blanked, the new value is visible to agents until the next route change or subtree addition re-triggers a scan.Pre-#176 this was masked because the meta was detached — any framework write landed on a node nobody was reading.
Gap 2 —
noscript-strip: children re-rendered into a kept<noscript>aren't recognizedstripNoscript(extension/src/rules/noscript-strip.ts:46) is downward-only: it matches when the watcher subtree is a<noscript>or contains one. When new children are added into a<noscript>we already blanked, the watcher fires on the new children, butstripNoscriptwalks downward — it doesn't recognize that the added subtree's ancestor is a noscript.Pre-#176 this was masked because the noscript was gone, so any new content had to bring its own
<noscript>wrapper. Real-world likelihood is very low: frameworks essentially never re-render noscript children at runtime.Proposed fix
OBSERVED_ATTRIBUTES(or expose a per-subscriberattributeFilter) socontentmutations on meta elements reachmeta-injection-strip, and have the rule subscribe withobserveAttributes: true.closest(\"noscript\")check insidestripNoscriptso a subtree added under a kept noscript is recognized as noscript content.Out of scope
html-comment-striprecoverage — tracked separately.INJECTION_PATTERNSaudit on attribute-targeted rules — tracked separately.