| name | dom-vulnerability-static-analysis |
| description | Static code analysis for DOM-based vulnerabilities in client-side JavaScript -- source/sink enumeration via grep and AST tools, data flow tracing, sanitization assessment, and framework-specific sink detection. Use when performing pre-commit reviews, auditing large codebases without dynamic execution, or triaging minified code for XSS issues. |
Static analysis framework for DOM XSS -- no dynamic execution needed.
1. Enumerate sources and sinks
rg 'innerHTML|outerHTML|document\.write|insertAdjacentHTML|\.html\(' \
--type js --type ts -n src/
rg 'eval\(|new Function\(|setTimeout\([^,]*["\x27]|setInterval\([^,]*["\x27]' \
--type js --type ts -n src/
rg 'location\.(href|assign|replace)\s*=|window\.open\(' \
--type js --type ts -n src/
rg 'location\.(hash|search|href)|document\.URL|document\.referrer|window\.name|postMessage' \
--type js --type ts -n src/
rg 'dangerouslySetInnerHTML|v-html|ng-bind-html|\[innerHTML\]|hx-get|hx-post' \
--type js --type html -g "*.vue" -g "*.tsx" -n src/
Checkpoint: Record total sink count and source count. If sinks > 50, prioritize by category (eval-family first, then innerHTML, then URL assignment).
2. Trace data flow (source -> sink)
For each sink hit, trace backwards to determine if attacker input reaches it:
rg "content\s*=" --type js -n src/ | rg -i "location|param|query|hash|input|request"
Classify each finding:
- Direct flow: source -> sink with no sanitization = vulnerability
- Sanitized flow: source -> sanitizer -> sink = check sanitizer adequacy
- Static content: hardcoded string -> sink = not exploitable
3. Assess sanitization
rg "DOMPurify|dompurify|sanitize\(" --type js --type ts -n src/
rg "function.*(sanitiz|escape|clean|filter)" --type js --type ts -n src/
For custom sanitizers: apply the custom-sanitizer-audit skill (Five-Point Checklist).
For DOMPurify: check version and config -- see dompurify-mxss-bypass skill.
Checkpoint: For each custom sanitizer found, read the implementation. A function named escapeHTML that is NOT a standard library must be reviewed for bypass potential before marking flows through it as safe.
4. AST-based analysis (large codebases)
rg patterns are fragile for code constructs — they miss variations in whitespace, nesting, and comments. Use AST-based tools for structural matching.
ast-grep (installed in runtime)
ast-grep uses tree-sitter for structural code matching. Patterns use real code syntax with $VAR wildcards — far more accurate than regex for function calls, assignments, and nested expressions.
ast-grep -p '$EL.innerHTML = $VAR' -l js src/
ast-grep -p '$EL.outerHTML = $VAR' -l js src/
ast-grep -p '$EL.insertAdjacentHTML($POS, $CONTENT)' -l js src/
ast-grep -p 'eval($INPUT)' -l js src/
ast-grep -p 'new Function($BODY)' -l js src/
ast-grep -p 'location.href = $VAR' -l js src/
ast-grep -p 'location.assign($URL)' -l js src/
ast-grep -p 'window.open($TARGET)' -l js src/
ast-grep -p 'window.addEventListener("message", $HANDLER)' -l js src/
ast-grep -p 'dangerouslySetInnerHTML={{$VAR}}' -l tsx src/
ast-grep -p '$EL.html($CONTENT)' -l js src/
Add --json to any command for structured output with file paths, line/column positions, and captured metavariable values. This is useful for programmatic triage or feeding results into jxscout custom analyzers.
Additional AST tools (if operator-installed)
- Semgrep:
semgrep --config p/javascript for DOM XSS rules (includes taint tracking in Pro)
- CodeQL:
javascript/ql/src/Security/CWE-079 for data-flow taint analysis
- ESLint:
no-unsanitized/property, no-unsanitized/method
5. Report findings
For each confirmed source-to-sink flow:
- File, line number, sink type
- Source of attacker input
- Sanitization present (yes/no, adequate/inadequate)
- Exploitability assessment
- Recommended fix
Chain With
dom-vulnerability-detection (dynamic analysis), csp-bypass (CSP blocks), custom-sanitizer-audit (homegrown sanitizer), dompurify-mxss-bypass (DOMPurify)