git:20260504.2a64374 to git:20260528.f3e4348

69 added, 195 removed. Audit B to A.

---
name: dom-vulnerability-static-analysis
- description: Static code analysis for DOM-based vulnerabilities in client-side JavaScript. USE WHEN performing pre-commit reviews, auditing large codebases without dynamic execution, triaging minified code for XSS issues, verifying sanitization routines, analyzing source-to-sink data flows, OR reviewing JavaScript files for potential DOM XSS. Covers source identification, data flow tracing, sink detection, sanitization assessment, postMessage handler review, framework-specific constructs, and automated pattern scanning with AST-based tools.
+ 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.
---
- # DomVulnerabilityStaticAnalysis
-
- Static code analysis framework for identifying DOM-based vulnerabilities in client-side JavaScript without dynamic execution.
-
- ## Overview
-
- DOM-based vulnerabilities occur when untrusted data flows from a source to a sink entirely on the client. Static analysis involves examining the source code to identify these flows without executing the page. According to Intigriti's guide, hunting DOM-based XSS via static code analysis requires manually reviewing JavaScript files, searching for DOM sources, and tracing references forward through the code. Mozilla's research stresses that to avoid DOM XSS bugs we need to inspect patterns where a string is parsed into HTML, such as assignments to innerHTML or outerHTML, calls to insertAdjacentHTML(), and document.write().
-
- ## When to Use This Skill
-
- Activate this skill when:
-
- * You must audit JavaScript for DOM-based vulnerabilities but cannot run the code in a browser (e.g., during pre-commit reviews or reviewing minified code)
- * You need to triage large codebases for potential XSS issues and create high-signal leads for further manual inspection
- * You want to verify whether existing sanitisation routines correctly protect assignments to DOM sinks
- * You are performing automated security scanning at scale
- * You need to analyze minified or obfuscated JavaScript files
-
- ## Static Analysis Methodology
-
- The static analysis process can be broken down into the following steps. Be systematic and record all findings for follow-up testing.
-
- ### 1. Identify Attacker-Controlled Sources
-
- Begin by listing all the JavaScript constructs that can carry user input:
-
- * **URL components:** `window.location`, `location.search`, `location.hash`, `location.pathname`, and related properties
- * **Document referrer:** `document.referrer`
- * **Cookies and storage:** `document.cookie`, `localStorage`, `sessionStorage`
- * **Window name:** `window.name`
- * **Post messages:** `event.data` in message handlers
- * **Third-party inputs:** Data returned from APIs, query parameters passed into functions, and imported JSON or YAML files
-
- Search across the codebase for these properties. Use a case-sensitive search (grep, ripgrep, or your IDE's find-in-files) to build a list of occurrences. For minified or obfuscated files, consider using a beautifier to improve readability.
-
- ### 2. Trace Data Flow to Sinks
-
- Once you locate a source, trace how the data moves through variables. Follow assignments, function arguments, and returns to determine where the value is eventually used. It may help to annotate the code with comments or to draw a simple flow diagram. Keep in mind that static analysis cannot determine the run-time value of a variable; treat any variable assigned from a source as untrusted until proven otherwise.
-
- ### 3. Locate Dangerous Sinks
-
- Identify places where untrusted data is inserted into the DOM or executed as code. Key patterns to look for include:
-
- | Sink Category | Examples |
- |---------------|----------|
- | **HTML injection** | Assignments to `.innerHTML` and `.outerHTML`, calls to `insertAdjacentHTML()`, `document.write()` and `document.writeln()`, jQuery's `.html()` and `.append()` methods |
- | **Code execution** | `eval()`, `Function()`, `setTimeout()/setInterval()` when called with a string, or constructing `<script>` elements with dynamic src attributes |
- | **URL redirection** | Assignments to `location`, `location.href`, `location.assign()`, `window.open()` and setting src/href attributes on `<a>`, `<iframe>`, `<img>`, etc. |
- | **Template evaluation** | Framework-specific directives such as AngularJS `ng-init`, Vue `v-bind`/`v-on`, or htmx `hx-on` that interpolate expressions |
-
- Write down each instance where data flows from an untrusted variable into one of these sinks. If the right side of an assignment is a literal string, it is usually safe. Otherwise, proceed to the next step.
-
- ### 4. Assess Sanitisation and Validation
-
- Review any filtering or sanitisation logic applied to the data before it reaches a sink. Ask these questions:
-
- * **Is a sanitizer used?** Functions like `DOMPurify.purify()` are recognised as safe in tooling like Mozilla's ESLint plugin. If the code calls a known sanitizer (e.g., `DOMPurify.sanitize()`, `escapeHTML()`), it is likely safe.
- * **Are regex patterns robust?** Filters must anchor both the beginning and end of the string. Patterns such as `/([a-zA-Z0-9]+|\s)+$/` allow attackers to prepend malicious content. Ensure the pattern uses `^` and `$` to bound the entire string.
- * **Do URL validators parse correctly?** Functions that call `new URL()` may misparse schemes if the input is malformed. Reject ambiguous formats like `https:example.com` and validate both protocol and host.
- * **Are types enforced?** Static analysis cannot inspect run-time types, so treat any input that is not explicitly converted or validated as a potentially dangerous string. Arrays or objects may call custom `toString()` methods that return `javascript:` schemes. Confirm type checking is in place.
-
- Document any sanitisation functions encountered. Where the filter logic appears insufficient or absent, flag the instance for further review.
-
- **⚠️ Critical Warning:** If a function is called `escapeHTML` but it IS NOT a standard library function, you should review the function FIRST before flagging it as safe. A common pattern is developers naming their own validation functions which can often be bypassed.
-
- * If this is the case, examine the function and understand how it could be bypassed and deem it weak or insecure.
-
- ### 5. Examine postMessage Handlers
-
- Cross-origin messaging is handled via `window.postMessage()`. When reviewing static code:
-
- 1. **Locate handlers:** Search for `addEventListener('message', ...)` and assignments to `onmessage`.
- 2. **Check origin validation:** Ensure the code compares `event.origin` to a trusted, exact origin rather than using `startsWith()` or `includes()`. Static analysis should flag comparisons to `window.origin` or cases where no origin check is performed. Accept only messages from known domains.
- 3. **Validate message data:** Avoid executing functions based on `event.data`. Look for patterns like `window[data.func](data.payload)` and flag them. Data should be parsed (e.g., `JSON.parse()`) and validated against a strict schema before use.
-
- ### 6. Review Framework-Specific Constructs
-
- Modern frameworks introduce their own templating and directive mechanisms. When reviewing code, search for:
-
- * **AngularJS:** Look for `ng-init`, `ng-app`, or double curly `{{...}}` interpolation. If user input is bound inside these expressions without sanitisation, it may trigger client-side template injection.
- * **Vue.js:** Look for `v-bind:`, `v-on:`, and mustache syntax. Binding untrusted data directly can lead to execution of functions such as `this.constructor.constructor('alert(1)')()`.
- * **htmx:** Check attributes like `hx-on`, `hx-trigger`, and `hx-target`. Malformed attribute names or values may break parsing rules and execute injected code.
-
- Flag any directive or binding where user data is inserted into template expressions or directive attributes.
-
- ### 7. Perform En-Masse Pattern Scanning
-
- For large codebases, manual inspection is impractical. Use automated searches to highlight high-risk patterns:
-
- 1. **Regex scanning:** Search for assignments to known sinks using regular expressions (e.g., `\.innerHTML\s*=`, `\.outerHTML\s*=`, `insertAdjacentHTML\(`, `document\.write\(`). Tools like ripgrep can search recursively and provide line numbers. Once this is done, it is vital to trace and understand context to understand if the flow is accessible, how it is accessible and what sources can reach it.
-
- 2. **AST-based tools:** Consider using linting plugins or static analysis tools such as `eslint-plugin-no-unsanitized` (for JavaScript) which parse the Abstract Syntax Tree and differentiate between hardcoded literals and variables. These tools reduce false positives and highlight flows that require review.
-
- 3. **Source-to-sink analysis:** If your tooling supports taint analysis, run it to automatically trace untrusted sources to sinks. Treat any flagged path as a high priority for manual verification.
-
- 4. **Whitelisting safe patterns:** Maintain a list of approved sanitisation functions (e.g., `DOMPurify.purify`, `escapeHTML`) and configure your scanner to treat assignments wrapped in these functions as safe. Anything else should be flagged for human review. Remember, if a function is called `escapeHTML` but it IS NOT a standard library, you should review the function FIRST before flagging it as safe. A common pattern is developers naming their own functions to validate which can often be bypassed.
- * If this is the case, examine the function and understand how it could be bypassed and deem it weak or insecure.
-
- Document the results in a spreadsheet or issue tracker. For each finding, record the file, line number, source variable, sink call, and any sanitiser observed. This helps prioritise follow-up audits.
-
- ### 8. Flag and Communicate Findings
+ Static analysis framework for DOM XSS — no dynamic execution needed.
- Static analysis produces potential vulnerabilities, not definitive exploits. For each flagged instance:
+ ## 1. Enumerate sources and sinks
- * **Describe the source–sink flow:** Indicate the untrusted input and the sink it reaches. Example: "queryParam → innerHTML without sanitisation."
- * **Assess sanitisation:** Note whether a recognised sanitiser is used or if a custom filter appears weak (e.g., regex missing anchors).
- * **Prioritise by risk:** Highlight sinks that lead to code execution (`eval`, `Function`) and critical flows like client-side redirects. Provide examples of potential payloads to illustrate impact.
- * **Recommend remediation:** Suggest encoding output, validating inputs, using frameworks' safe APIs (e.g., `textContent` instead of `innerHTML`), or introducing Trusted Types. Encourage developers to adopt automated linting to prevent regressions.
+ ```bash
+ # Find all dangerous sinks
+ grep -rn 'innerHTML\|outerHTML\|document\.write\|insertAdjacentHTML\|\.html(' \
+ --include="*.js" --include="*.jsx" --include="*.ts" --include="*.tsx" src/
- ## High-Signal Patterns for Static Review
+ # Find eval-family sinks
+ grep -rn 'eval(\|new Function(\|setTimeout([^,]*["\x27]\|setInterval([^,]*["\x27]' \
+ --include="*.js" --include="*.ts" src/
- During static analysis, prioritise the following patterns as they often indicate vulnerabilities:
+ # Find URL assignment sinks
+ grep -rn 'location\.\(href\|assign\|replace\)\s*=\|window\.open(' \
+ --include="*.js" --include="*.ts" src/
- 1. Assignments to `.innerHTML`/`.outerHTML` with a variable rather than a literal string
- 2. Calls to `document.write()`, `document.open().write()`, `append()` or `html()` where the argument is user-controlled
- 3. Construction of `<script>`, `<iframe>`, or `<img>` elements with dynamic src/href attributes derived from user input
- 4. Functions that build URLs by concatenating strings rather than using safe URL constructors, and then assign them to `location` or `window.open()`
- 5. Regex validations that do not anchor the start and end of the string
- 6. Origin checks in postMessage handlers that use `startsWith()` or compare to `window.origin` instead of explicit allowed origins
- 7. Conditional logic that branches on untrusted data and calls dynamic execution functions like `eval()`, `Function()`, or `setTimeout()`
- 8. Framework directives or template interpolations that embed variables without sanitisation
+ # Find attacker-controlled sources
+ grep -rn 'location\.\(hash\|search\|href\)\|document\.URL\|document\.referrer\|window\.name\|postMessage' \
+ --include="*.js" --include="*.ts" src/
- ## Automated Scanning Tools
+ # Framework-specific sinks
+ grep -rn 'dangerouslySetInnerHTML\|v-html\|ng-bind-html\|\[innerHTML\]\|hx-get\|hx-post' \
+ --include="*.js" --include="*.tsx" --include="*.html" --include="*.vue" src/
- Consider using these tools to accelerate static analysis:
+ # AngularJS CSTI: user input bound to scope then evaluated in {{ }} templates
+ # Payload: {{constructor.constructor('alert(1)')()}} (sandbox escape for AngularJS 1.x)
+ grep -rn 'ng-app\|ng-bind\|\$scope\.\|ng-model\|ng-bind-html' \
+ --include="*.html" --include="*.js" src/
- * **eslint-plugin-no-unsanitized** - Mozilla's ESLint plugin that detects unsafe DOM manipulation
- * **Semgrep** - Pattern-based code scanner with DOM XSS rules
- * **CodeQL** - GitHub's semantic code analysis engine with JavaScript security queries
- * **ripgrep/grep** - For quick regex-based searches across codebases
- * **js-beautify** - For deobfuscating and formatting minified JavaScript before analysis
+ # Prototype pollution sources: Object.assign/spread with user-controlled input
+ grep -rn 'Object\.assign\|\.\.\..*param\|\.\.\..*query\|merge(' \
+ --include="*.js" --include="*.ts" src/
+ ```
- ## Analysis Workflow
+ ## 2. Trace data flow (source → sink)
- Follow this systematic workflow for large codebases:
+ For each sink hit, trace backwards to determine if attacker input reaches it:
+ ```bash
+ # Find the variable assigned to the sink, then trace its origin
+ # Example: el.innerHTML = content → where does `content` come from?
+ grep -rn "content\s*=" --include="*.js" src/ | grep -i "location\|param\|query\|hash\|input\|request"
```
- 1. Setup
- ├─ Collect all JavaScript files
- ├─ Deobfuscate/beautify minified code
- └─ Set up linting tools (ESLint, Semgrep)
- 2. Automated Scan
- ├─ Run AST-based tools (eslint-plugin-no-unsanitized)
- ├─ Run pattern matchers (Semgrep/CodeQL)
- ├─ Search for source patterns (location.*, document.cookie, etc.)
- └─ Search for sink patterns (.innerHTML, eval, etc.)
+ 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. Manual Triage
- ├─ Review each flagged instance
- ├─ Trace data flow from source to sink
- ├─ Assess sanitization effectiveness
- └─ Document findings with risk rating
+ ## 3. Assess sanitization
- 4. Reporting
- ├─ Categorize by severity (Critical/High/Medium/Low)
- ├─ Provide proof-of-concept payloads
- ├─ Recommend specific remediation
- └─ Track fixes and retest
+ ```bash
+ # Find DOMPurify usage
+ grep -rn "DOMPurify\|dompurify\|sanitize(" --include="*.js" --include="*.ts" src/
+
+ # Find custom sanitizers
+ grep -rn "function.*sanitiz\|function.*escape\|function.*clean\|function.*filter" \
+ --include="*.js" --include="*.ts" src/
```
- ## Examples
+ For custom sanitizers: apply the `custom-sanitizer-audit` skill (Five-Point Checklist).
+ For DOMPurify: check version and config — see `dompurify-mxss-bypass` skill.
- **Example 1: Scan codebase for innerHTML assignments**
- ```
- User: "Find all potentially unsafe innerHTML assignments in this repository"
- → Use ripgrep to search for \.innerHTML\s*= patterns
- → Filter out assignments with literal strings
- → Trace remaining assignments back to data sources
- → Flag flows from location.*, document.referrer, or event.data
- → Generate report with file paths, line numbers, and risk assessment
- ```
+ ## 4. AST-based analysis (optional)
- **Example 2: Audit custom sanitization function**
- ```
- User: "Review this escapeHTML function to see if it's secure"
- → Read function implementation
- → Check if it uses proper encoding (HTML entity encoding)
- → Test against known bypass patterns (<img src=x onerror=alert(1)>)
- → Verify it handles all contexts (attributes, text nodes, URLs)
- → Report weaknesses and recommend using DOMPurify instead
- ```
+ For large codebases, use tooling:
+ - **Semgrep**: `semgrep --config p/javascript` for DOM XSS rules
+ - **CodeQL**: `javascript/ql/src/Security/CWE-079` for taint tracking
+ - **ESLint**: `no-unsanitized/property`, `no-unsanitized/method`
- **Example 3: Triage large JavaScript bundle**
- ```
- User: "This 5MB minified bundle may have DOM XSS vulnerabilities"
- → Beautify the bundle using js-beautify
- → Run eslint-plugin-no-unsanitized across the formatted code
- → Search for high-risk patterns (eval, Function, innerHTML assignments)
- → Prioritize findings by examining source-to-sink flows
- → Create ranked list of vulnerabilities for manual verification
- ```
+ ## 5. Cross-validate findings
- **Example 4: Analyze postMessage handler security**
- ```
- User: "Check if these postMessage handlers are secure"
- → Search for addEventListener('message', ...) patterns
- → Extract each handler function
- → Verify presence of event.origin validation
- → Check if validation uses strict equality (===) with whitelisted origins
- → Look for dangerous patterns like window[event.data.func]()
- → Document insecure handlers with exploitation scenarios
- ```
+ Before reporting, reduce false positives by cross-referencing:
+ - Compare grep-based sink hits (steps 1-2) against AST taint-tracking results (step 4) — a finding confirmed by both methods is high-confidence
+ - For grep-only hits: manually verify the data flow in context (minified code aliasing can produce false matches)
+ - For AST-only hits: confirm the sink pattern wasn't missed by grep regex limitations
+ - Discard any finding where the source is provably non-attacker-controlled after contextual review
- ## References
+ ## 6. Report findings
- * [PortSwigger Web Security Academy – DOM-based XSS](https://portswigger.net/web-security/cross-site-scripting/dom-based)
- * [Intigriti – Hunting DOM XSS via Static Code Analysis](https://blog.intigriti.com)
- * [Mozilla – eslint-plugin-no-unsanitized](https://github.com/mozilla/eslint-plugin-no-unsanitized)
- * [Practical CTF: Cross-Site Scripting and postMessage Exploitation](https://google.com)
- * Youssef Sammouda – DOM XSS write-ups
- * [Client-Side Security](https://book.jorianwoltjer.com/web/client-side)
- * [XSS Deep Dive](https://book.jorianwoltjer.com/web/client-side/cross-site-scripting-xss)
- * [WebSockets Security](https://book.jorianwoltjer.com/web/client-side/websockets)
+ 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
- ---
+ ## 7. Library-specific XSS gadgets
- **License:** CC-BY-4.0
+ See `GADGETS.md` for jQuery `.text()` re-decoding, moment.js format injection, and `javascript:` URI hostname bypass patterns.
- This skill provides a comprehensive checklist for static analysis of client-side code. It complements dynamic testing by identifying flows worth exploring further when run-time analysis is possible.
+ ## Chain With
+ - `dom-vulnerability-detection` (dynamic analysis), `csp-bypass` (CSP blocks), `dompurify-mxss-bypass` (DOMPurify), `aem-sling-exploitation` (AEM-specific XSS gadgets)