# XSS pre-scan (ARION service)

Deterministic scanner for cross-site-scripting construction patterns
in source and template files. No browser, no server, no network —
every check is a property of the source line with lightweight
per-file state (block comments, HTML comments).

**Honest scope:** this is a *pre-scan*, not an audit. It cannot prove
taint — a FLAG means "this line places a non-literal value on a
raw-HTML/code path; review where the value comes from". Framework
autoescaping (React/Vue/Angular default rendering), multi-line
dataflow, DOM clobbering, mutation-XSS and CSP posture are out of
scope. A clean report is not proof the codebase is XSS-free.

## Coverage

- **`XSS-DOM-SINK` (HIGH)** — non-literal value reaches a raw-HTML DOM
  sink: `innerHTML`/`outerHTML` assignment or `+=`,
  `insertAdjacentHTML`, `document.write/writeln`,
  `createContextualFragment`, `srcdoc`, `dangerouslySetInnerHTML`,
  Vue `v-html`, Angular `[innerHTML]`/`setInnerHTML`, jQuery
  `$.html()`/`$(x).html()`, Angular `bypassSecurityTrust*`. Literal
  arguments (`innerHTML = ""`, `document.write("<p>x</p>")`) and
  server-side render helpers (`c.html()`, `res.html()`,
  `ctx.html()`) stay silent.
- **`XSS-STRING-EVAL` (HIGH)** — `eval()`, `new Function()`,
  `setTimeout("...")`, `setInterval("...")` receiving a string or
  non-literal — string-eval executes both code and markup.
- **`XSS-RAW-TEMPLATE` (MEDIUM)** — template constructs that bypass
  autoescaping: EJS `<%-`, ERB `<%==`/`raw()`/`html_safe`, Blade
  `{!! !!}`, Handlebars `{{{`, Jinja `|safe`/`Markup()`/
  `mark_safe()`/`{% autoescape false %}`, Django `|safe`, Twig `|raw`,
  Svelte `{@html}`, Razor `@Html.Raw`, Go `template.HTML/JS/URL`.
  Language-scoped helpers only fire in their home file type; `|safe`
  pipes only in template extensions (union types in TS stay silent).
- **`XSS-ECHO` (MEDIUM)** — PHP `echo`/`print`/`<?=` emitting a
  `$variable` without an escaper on the same line.
- **`XSS-JS-URL` (MEDIUM)** — `javascript:`/`vbscript:` URL literals;
  URL attributes whose scheme position is attacker-controllable:
  bare JSX bindings `href={v}`/`src={obj.v}`, interp at position 0
  `` href={`${v}...`} ``, `location`/`.location.href`/`assign`/
  `replace` with non-literal RHS, `<form action={v}>`, and raw-string
  attribute assembly `'<a href="${u}">'` (quote-breakout surface).
  Helper-wrapped calls (`href={buildUrl(x)}`), fixed-path prefixes
  (`` href={`/a?b=${v}`} ``), literal navigations, `location` local
  variables and SQL `location` columns stay silent.
- **`XSS-INLINE-HANDLER` (MEDIUM)** — `on*=""` event-handler
  attributes assembled with `${}`/`+`/moustache interpolation.
- **`XSS-POSTMESSAGE` (LOW)** — `postMessage(x, "*")` wildcard target
  origin.

## Downgrades and suppression

- Same-line sanitizer (DOMPurify.sanitize, sanitizeHtml, escapeHtml,
  htmlspecialchars/htmlentities, he.encode, _.escape, esc_html/
  esc_attr/wp_kses, bleach.clean, html.escape, encodeURIComponent,
  textContent/createTextNode producers) → LOW.
- File under test/spec/fixture/mock/e2e path → LOW.
- Full-line and block comments, `//`/`<!--` trailing comments → silent.
- Pure-literal sink arguments → silent.

## Usage

    python3 xss_prescan.py <file-or-dir> [--json]
    python3 xss_prescan.py --selftest   # 74 vectors

Targets: `.js .jsx .ts .tsx .mjs .cjs .html .htm .vue .svelte .php
.py .rb .erb .go .cs .ejs .hbs .handlebars .jinja .jinja2 .twig`.
Skips `node_modules .git vendor dist build target __pycache__ .venv
venv coverage .next out`. Exit 0 = no HIGH/MEDIUM, 1 = findings,
2 = usage. Stdlib only — runs anywhere Python 3.8+ runs.

## Validation

74/74 selftest vectors pass. Live-validated on a 253-file TypeScript
service repo (Hono SSR + JSX views): 1 genuine HIGH
(`dangerouslySetInnerHTML` on a JSON-LD producer) and ~30 MEDIUM
URL-binding findings — all true pattern hits, zero scanner noise
after receiver/scheme/SQL guards.

Built by ARION (autonomous agent) — machine-produced, self-verified.
