Feat/xss sanitizer - #4
Merged
Merged
Conversation
DOMPurify is rejected on capability grounds: it needs a live DOM, which React Native cannot provide. js-xss is pure JS, sync, and works in browser, Node, and Metro. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Prototyping against xss 1.0.15 surfaced two constraints now recorded in the spec: cid: URIs are dropped by the default src scheme allowlist and must be preserved explicitly, and xss's dynamic CJS exports break ESM named imports so it must be consumed via its default export. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The mXSS test asserted a substring was absent when xss correctly escapes it inside an allowlisted title attribute, and the blocking filter instance was declared a task before its first consumer, failing no-unused-vars. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
As written the pattern replaced only the scheme prefix, leaving the remote host visible in the output. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The snapshot baseline is 498 MB because inline images are embedded as base64 data URIs, so a snapshot diff is unreviewable. Compare the base and new renderers structurally instead, aggregating lost tags, lost attributes and visible-text loss across the corpus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Corrected fidelity sweep (attributing drops to a surviving vs. removed tag, and excluding HTML comments from the visible-text metric) over the 1000-fixture corpus found five attributes genuinely dropped from tags that survived sanitization, each changing visible rendering: - body link/vlink (default/visited link color) - 681 fixtures - ol start/type (list numbering) - 102/94 fixtures - ul type (bullet style) - 91 fixtures - hr width/size (rule length/thickness) - 160/159 fixtures - br clear (text wrap around floats) - 43 fixtures All other candidates in the corrected report (Outlook Safe Links metadata, mso-list CSS fragments, inline style value tokens split by the diff script, tabindex, rel, name, div link/vlink which browsers only honor on body) were verified to have no visible rendering effect and were left alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
<style> was allowlisted as an ordinary tag, so xss routed its contents
through the normal element-content pipeline: HTML comments got stripped
(destroying Outlook's canonical <style><!-- ... --></style> export) and
`>` got escaped to `>` (breaking child-combinator selectors, which a
browser never decodes back since <style> text is never HTML-parsed). A
comment that swallowed the real closing </style> also produced
unbalanced output capable of suppressing the rest of the document,
including the attachment list.
Fix: extract every <style>...</style> block before process() runs into
a placeholder token (collision-checked against the input, extended
deterministically rather than via Math.random()), and splice the raw
contents back in verbatim afterward. A block whose contents contain a
literal </style or <script is dropped rather than reinserted. Only a
safe `media` attribute is carried over; nothing else is. Re-measured
across the 1000-fixture corpus (861 fixtures with a genuine, non-IE-
conditional-comment-gated <style> block): fixtures losing their entire
stylesheet dropped from 774 to 0, CSS bytes lost from ~1.6 MB to 0,
unbalanced <style>/</style> outputs from 1 to 0.
Also closes two blockRemoteImages bypasses found in the same pass:
- REMOTE_CSS_URL didn't match double-quoted CSS url("...") because
defaultSafeAttrValue escapes " to " before the pattern runs, so
a tracking-pixel URL in that form survived untouched. Now matches
the escaped-quote forms too, and consumes the trailing quote so the
single-quoted case no longer leaves a stray quote in the output.
- srcset was only checked against its first comma-separated candidate
(REMOTE_URL is ^-anchored over the whole value). Now every candidate
is checked; the attribute is blanked if any one is remote.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…expression' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
add sanitizer using xss