Skills

Xss Browser Confirm

Turn a suspected Cross-Site Scripting reflection or DOM sink into proof of JavaScript...

Install

npx skills add vigolium/vigolium --skill xss-browser-confirm -g -a claude-code -y
Repository
vigolium/vigolium1.1k
Category
Writing
Updated
10d ago
License
MIT
Context cost
Mediumabout 1,855 tokens
Runs scripts
No, instructions only

What it does

Turn a suspected Cross-Site Scripting reflection or DOM sink into proof of JavaScript execution by firing a uniquely-tagged dialog in a real headless browser via the browser_probe tool, not by string-matching the response. Covers reflected, stored, and DOM-based XSS, context-aware payload crafting (HTML body, attribute, JS string, URL/href, DOM sink), light WAF/encoding evasion when a payload reflects but doesn't execute, and persisting a finding sized by real impact. Use when a parameter's value appears in the response, when a DOM sink (innerHTML, document.write, eval, location) consumes input, when CWE-79 was flagged, or when a scanner saw reflection but couldn't confirm execution.

XSS → Browser-Confirmed Execution

You suspect XSS somewhere. Reflection is a hint, not proof. Your job is to make JavaScript actually run in a real browser and capture the proof, then persist a finding with the exact URL that executed. browser_probe loads a URL in headless Chrome and reports any alert/confirm/prompt dialog that fires, even when nothing reflects visibly in the HTML. That dialog is your oracle.

When this skill applies

  • A URL/body/header param value appears in the response body or a header.
  • A scanner/audit flagged CWE-79, "reflected XSS", "DOM XSS", or "reflection observed, execution unconfirmed".
  • The page's JS feeds input into a sink: innerHTML, outerHTML, document.write, eval, setTimeout(string), location/href, $(...).html(), dangerouslySetInnerHTML.

If you only have "fuzz everything", anchor on a record first (query_records for reflected params / search endpoints, then inspect_record). Don't probe blind.

The canary discipline

Use one unique canary per probe so a dialog can't be a coincidence or a leftover from another page. Make it specific and greppable, e.g. alert('xss-9f3a2c'). After browser_probe, the proof is dialog_fired == true and the dialog message equals your canary. A dialog with a different message is the app's own JS, not your finding.

remember the canary + target as xss-target so it survives context churn.

Workflow

1. Anchor and find the reflection / sink

inspect_record the candidate. Find where the input lands:

  • In the response body → reflected; note the surrounding bytes.
  • Consumed by client JS with no server reflection → DOM-based; read the JS to find the sink and the source (location.hash, location.search, document.referrer, postMessage).
  • Persisted then rendered on another page (profile, comment, admin panel) → stored; note the injection request and the rendering URL.

2. Classify the injection context

Read the whole SKILL.md on GitHub

More in Writing