#04A03 · A05 · A07
XSS / CSRF / CORS
Client-side injection, cross-site request forgery, and cross-origin misconfiguration.
How to use this prompt
- 1Install SecureNow in your project (then optionally
npx securenow login):$ npm install securenow - 2Copy the prompt below and paste it into your AI coding agent (Claude Code, Cursor, Codex…) opened at the root of your project.
- 3It generates four files into
threat/04-xss-csrf-cors/— openxss-csrf-cors-code-findings.html(the audit) andxss-csrf-cors-detection-mitigation.html(the defenses) in your browser.
🔒Runs entirely in your environment — your codebase is never uploaded or shared. The generated HTML reports are self-contained and work offline.
The prompt
# XSS / CSRF / CORS Threat Model — Generator Prompt
A **copy-paste prompt** for customers. Paste the entire prompt below into an AI coding agent
(Claude Code, Cursor, Codex, …) opened at the root of **any project** that has the
`securenow` CLI installed and logged in. The agent will inventory the browser-facing &
cross-origin surface, build an exhaustive **client-side injection & cross-origin trust**
threat model mapped to the **OWASP Top 10:2021** and the relevant client-side CWEs
(CWE-79 XSS, CWE-352 CSRF, CWE-942 permissive CORS, CWE-1021 clickjacking/UI redress,
CWE-601 open redirect), audit the code for these flaws, and emit a SecureNow-branded
**two-track deliverable set** in **Markdown + self-contained HTML** — a **Detection &
Mitigation** runbook (the detection rules to create, the mitigation commands to run, how to
test each one) and a **Code Findings & Recommendations** report (the code-level findings,
audited, **not** fixed) — including which threats still need the SecureNow team. Every alert
rule and command is **grounded in the SDK actually installed in the repo** and emitted as a
**ready-to-copy** unit (SQL → `rules/<name>.sql` → full `securenow alerts rules create …` →
dry-run test).
This model covers the **browser as the trust boundary**: how a page is tricked into running
attacker script (XSS), into sending forged state-changing requests (CSRF), into leaking data
across origins (CORS / `postMessage` / `window.opener`), or into being framed, redirected, or
content-sniffed. It is one of a family of complementary models. **Be honest about native
coverage: this is mostly an app/config-fix surface.** SecureNow sees **traffic** and
**events** at the edge; it can:
- **detect + synchronously block** request-borne XSS payloads via the **system XSS signature
rule + `instant.block`** (reflected `<script>`, `onerror=`, `javascript:`, event-handler,
and known mutation/encoding patterns carried in a URL/body/header) — its real contribution
here;
- **surface posture findings** from traffic (missing/weak CORS, missing security headers seen
on responses) and contain abusive sources (probe floods, payload fuzzers) at the edge.
It **cannot** mint a CSRF token, set `SameSite` on your cookies, add a `Content-Security-Policy`,
turn on `X-Frame-Options`/`frame-ancestors`, or sanitize a DOM sink — **those are app/config
fixes** and every such row in this report pairs the edge containment with the primary app fix.
> **Scope discipline.** This model owns **client-side XSS (reflected/stored/DOM/mutation),
> CSRF, CORS, clickjacking, security headers, `postMessage`, `window.opener`/`target=_blank`,
> open redirect, content-type/MIME confusion, and cookie scoping/flags.** It **does not
> re-model** server-side injection (SQLi/RCE/SSTI → [../06-injection/](../06-injection/)),
> session/credential security (cookie *issuance* & session theft → [../01-authentication/](../01-authentication/)),
> third-party script/CSP-supply-chain & SRI ([../05-client-side-supply-chain/](../05-client-side-supply-chain/)),
> or the state-change *authorization* impact of a successful CSRF
> ([../02-authorization/](../02-authorization/)). It references those reports and detects only
> the **traffic-observable** symptoms (payload probes, CORS-preflight anomalies) where
> SecureNow adds value.
Requirements on the customer machine: `npm i -g securenow && securenow login` (admin auth +
app runtime connected). Everything else is discovered by the agent.
---
<!-- ════════════════ COPY EVERYTHING BELOW THIS LINE ════════════════ -->
# Generate an XSS / CSRF / CORS Threat Model Report (SecureNow)
You are a senior application-security engineer specializing in client-side & cross-origin web
security. Produce an **exhaustive XSS / CSRF / CORS threat model for THIS codebase**, organized
along the **OWASP Top 10:2021** (esp. **A03:2021 Injection** for XSS, **A05:2021 Security
Misconfiguration** for headers/CORS/clickjacking, with **A01:2021 Broken Access Control** for
CSRF state-change impact and **A07/A08** where relevant) and the client-side CWEs (**CWE-79,
CWE-352, CWE-942, CWE-1021, CWE-601, CWE-1004, CWE-693, CWE-444**), mapped to **SecureNow**
detections and mitigations, with a ready-to-run action plan **and** a code-level audit of every
client-side/cross-origin flaw you find. You write **four** deliverables into
`threat/04-xss-csrf-cors/` (create the folder if needed) — **two tracks, each Markdown + a
self-contained HTML page** (inline CSS + offline copy buttons, no network requests):
1. `xss-csrf-cors-detection-mitigation.md` — the **operational runbook**: what to run in
SecureNow (detection rules, mitigation commands, tests, action plan).
2. `xss-csrf-cors-detection-mitigation.html` — same, self-contained HTML with **copy buttons**
on every command/SQL block.
3. `xss-csrf-cors-code-findings.md` — the **code audit**: issues found in the codebase + the
recommended fixes (described, never applied).
4. `xss-csrf-cors-code-findings.html` — same, self-contained HTML.
The two tracks **cross-link** each other (the gaps/instrumentation rows in the detection report
link to the relevant code finding, and vice-versa). Every alert rule and command must be
**grounded in the SDK actually installed in this repo** (Phase 0.5) and emitted as a
**ready-to-copy** unit (SQL → `rules/<name>.sql` → full `securenow alerts rules create …` →
dry-run test) — never a fragment, never a guessed flag.
Work in the phases below, in order. **Never invent facts**: if something is not in the
codebase or not returned by a CLI command, say "not found" — do not guess. **Do not modify
application code.** You are auditing: every code-level fix is *described in the report*, never
applied to the repo.
**Scope discipline.** This model owns **CWE-79 (XSS, all variants), CWE-352 (CSRF), CWE-942
(permissive CORS), CWE-1021 (clickjacking), CWE-601 (open redirect), CWE-1004 (sensitive
cookie without HttpOnly), CWE-693 (protection-mechanism failure → missing security headers),
CWE-444 (content-type/request smuggling at the parser edge)**. For **server-side injection**
(SQLi/RCE/SSTI/NoSQL/command), **session & credential security**, **third-party script / CSP
supply-chain & SRI**, and the **authorization impact** of a state change, do **not** re-derive
the deep model — list them in a "Deferred to sibling models" subsection, link those reports,
and only model their **traffic-observable** symptoms here where SecureNow adds value.
---
## Phase 0 — Verify SecureNow tooling
Run and record (use `--json` where supported):
```bash
securenow doctor # connectivity must be healthy
securenow whoami # admin auth + runtime app
securenow status --json # app key(s), environment, firewall state
securenow alerts rules --json # detection rules that already exist (incl. system signature rules)
securenow automation --json # blocklist automations that already exist
securenow challenge list --json # CAPTCHA / proof-of-work challenge rules
securenow env --json # resolved SDK config (service name, endpoints)
```
If the CLI is missing or not logged in, **stop** and tell the user to run
`npm i -g securenow && securenow login`, then re-run this prompt. Capture the **app key**
(UUID) — every rule and command in the report must use it. If multiple apps exist, ask the
user which app this codebase maps to before continuing. Note the **firewall state** and any
**system signature rules** (especially the **XSS** signature rule — and SQLi/RCE) already
present: the XSS signature + `instant.block` is the backbone of this model's request-borne
XSS coverage and must not be duplicated with hand-written pattern SQL.
---
## Phase 0.5 — Ground every rule & command in the INSTALLED SDK
Before writing any SQL or CLI, read the SecureNow SDK that is actually installed in this repo so
every alert rule and command is correct for THIS version — never guess flags, subcommands, event
names, or SQL columns:
```bash
cat node_modules/securenow/package.json # installed SDK version (record it in both reports)
ls node_modules/securenow # exported modules: events, sessions, register, run, …
ls node_modules/securenow/dist 2>/dev/null # built entrypoints / bundled CLI
npx securenow --help # top-level commands available in this version
npx securenow alerts rules --help # exact create flags: --name/--sql/--apps/--severity/--schedule/--nlp
npx securenow event --help # `event send` shape for synthetic tests
npx securenow ratelimit --help; npx securenow challenge --help
npx securenow blocklist --help; npx securenow automation --help; npx securenow trusted --help
```
If `node_modules/securenow` is absent, run `npm ls securenow`; if still missing, tell the user to
`npm i securenow` (or `npm i -g securenow`) and stop. EVERY command, flag, `track('…')` event
name, and SQL column you emit MUST be one the installed SDK/CLI actually exposes. If the installed
version lacks a capability this prompt references, emit the rule but annotate it
`# requires securenow >= <version>` instead of a broken command. Record the resolved version in
the appendix of BOTH reports.
In Phase 4 and Phase 5, treat `node_modules/securenow` + `--help` as the source of truth: the
`securenow/events` `track()` signatures, the `securenow alerts rules` SQL columns, and every
mitigation subcommand are discoverable there. Cross-check before emitting.
---
## Phase 1 — Inventory the browser-facing & cross-origin surface (codebase analysis)
Client-side & cross-origin security starts with knowing **what the browser actually renders,
trusts, and is allowed to talk to**. Document what is *actually exposed*, not what is intended.
Cover at minimum:
- **Rendering model & framework** — server-rendered HTML (templating engine: EJS/Handlebars/
Pug/Twig/Jinja/ERB/Razor/Blade), React/Vue/Svelte/Angular SPA, Next.js/Nuxt/Remix/SvelteKit
hybrid, htmx/Alpine, plain DOM. Note whether the framework **auto-escapes by default** and
where that escaping is **bypassed** (raw/triple-brace/`{@html}`/`v-html`/`dangerouslySetInnerHTML`).
- **XSS sinks (DOM & template)** — enumerate every dangerous sink reachable from user/URL/
storage input: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write(ln)`,
`dangerouslySetInnerHTML`, `v-html`, Svelte `{@html}`, Angular `[innerHTML]`/`bypassSecurityTrust*`,
jQuery `.html()/.append()/$()`, `eval`, `new Function`, `setTimeout/setInterval(string)`,
`element.setAttribute('href'|'src', …)`, `location`/`location.href`/`assign`/`replace`,
template literals injected into HTML, `Range.createContextualFragment`, `DOMParser`,
`Element.insertAdjacentText` misuse, and any custom HTML-string builder. For each: the source
it flows from (`location.*`, `URLSearchParams`, `document.referrer`, `window.name`,
`postMessage` data, `localStorage`/`sessionStorage`, server JSON echoed into the DOM).
- **Reflected / stored input echoed into responses** — request params, headers (User-Agent,
Referer), and stored fields (profile bio, comments, filenames, display names, support
tickets) rendered back into HTML, attributes, JS context, CSS context, or URL context. Flag
the **HTML context** each lands in (each needs a different encoding).
- **Markdown / rich-text / WYSIWYG / HTML-email** — any user content rendered as HTML:
markdown renderers (marked/markdown-it/remark/showdown), sanitizers present or absent
(DOMPurify/sanitize-html/bluemonday/ammonia), `allowedTags`/`allowedAttributes` config,
whether `target=_blank` links get `rel=noopener`, whether `javascript:`/`data:` URLs are
stripped, SVG handling.
- **CSRF posture** — for every **state-changing** route (POST/PUT/PATCH/DELETE, and any
**GET that mutates**): is there a CSRF token (synchronizer/double-submit), is it bound to the
session, verified on the server, constant-time compared? Cookie `SameSite` value
(`Strict`/`Lax`/`None`) and whether `None` carries `Secure`. Are mutations accepted as
`application/json` only, or also as `text/plain`/form-encoded (JSON-CSRF / simple-request
surface)? Login/logout CSRF. SPA token-in-header vs cookie auth. Framework defaults
(Django/Rails/Laravel/Express `csurf`/Next.js server actions origin check).
- **CORS policy** — locate every place CORS headers are set (framework `cors()` middleware,
manual `Access-Control-Allow-Origin`, gateway/CDN/edge config, cloud function config). For
each: is `Origin` **reflected** back, is it an **allowlist** or `*`, is
`Access-Control-Allow-Credentials: true` set, is the origin match a **weak regex**
(`endsWith`, unescaped dots, missing anchors, `startsWith`), is `null` origin accepted, are
`Access-Control-Allow-Methods/Headers` over-broad, what `Vary: Origin` is sent.
- **Security headers (response posture)** — for the main app + API responses, record presence
& value of: `Content-Security-Policy` (and `unsafe-inline`/`unsafe-eval`/wildcard/nonce/hash,
`report-only` vs enforcing), `Strict-Transport-Security` (max-age/includeSubDomains/preload),
`X-Content-Type-Options: nosniff`, `X-Frame-Options` / CSP `frame-ancestors`, `Referrer-Policy`,
`Cross-Origin-Opener-Policy`, `Cross-Origin-Embedder-Policy`, `Cross-Origin-Resource-Policy`,
`Permissions-Policy`. Where set (middleware/helmet/next.config/CDN), and which routes lack them.
- **Cookie scoping & flags** — every cookie the app sets: `HttpOnly`, `Secure`, `SameSite`,
`Domain` (over-broad?), `Path`, `__Host-`/`__Secure-` prefixes, lifetime. Flag session/auth
cookies readable from JS or scoped to a parent domain.
- **`postMessage` & cross-frame** — every `window.addEventListener('message', …)` handler:
does it check `event.origin` against an allowlist (not `*`, not `indexOf`/`includes`), does it
validate `event.source`, does it trust `event.data` into a sink? Every `iframe.contentWindow.postMessage(..., '*')`
sending to wildcard target. Embedded third-party frames / SDKs.
- **`window.opener` / `target=_blank`** — links/`window.open` to external or user-controlled
URLs without `rel="noopener noreferrer"` (reverse-tabnabbing); `noopener` policy.
- **Open redirect** — every redirect built from request input: `res.redirect(req.query.next)`,
`location = params.get('returnTo')`, `next`/`redirect_uri`/`callback`/`url`/`return`
parameters, post-login/post-logout redirects, OAuth `redirect_uri` echoing (defer the OAuth
flow itself to the auth model). Is the target validated against an allowlist / restricted to
same-origin paths?
- **Content-type / MIME / download surface** — endpoints serving user-controlled content
inline: file download/preview, avatar/image, exported HTML/CSV, blob/data URLs. Is
`Content-Type` correct & `nosniff` set, is `Content-Disposition: attachment` used for
untrusted content, can a user upload an `.html`/`.svg`/`.xml` served from the app origin?
(Reflected-download / MIME-sniff XSS.) Defer the upload *storage* model to file-upload.
- **Trusted Types & modern mitigations** — is `require-trusted-types-for 'script'` set, are
Trusted Types policies defined, is `eval`/inline-script CSP-blocked?
- **Auth-context of state changes** — which mutating routes act on the *session cookie* (CSRF
surface) vs a *bearer token in a header* (not CSRF-exploitable from a browser, but note it).
- **Telemetry privacy & redaction** — confirm the SecureNow SDK / log pipeline redacts
`Cookie`, `Set-Cookie`, `Authorization`, CSRF tokens, and any reflected secret before
ingestion, and that captured request URLs/bodies carrying XSS payloads don't themselves
become a stored-XSS vector in the dashboard. If not found, raise a high-severity finding.
- **SecureNow instrumentation already present** — `securenow/register` / `securenow run` /
`securenow init` (auto traffic spans), any `securenow/events` `track()` calls, and whether
the firewall + the **XSS signature rule** are engaged. This determines what works *today* vs
*after instrumentation*.
Output of this phase = the report's **Surface & inventory** section: the **XSS sink map**
(sink → source → context → escaping?), the **reflected/stored input map**, the **CSRF posture
table** (route / method / token? / SameSite / content-type), the **CORS policy table**
(location / origin handling / credentials / weakness), the **security-header matrix** (header →
present? → value → routes missing), the **cookie-flags table**, the **`postMessage`/opener/redirect/MIME**
lists, the **telemetry redaction status**, and a short paragraph naming the real client-side
attack surface for this stack.
---
## Phase 2 — Enumerate threats (exhaustive catalog)
Evaluate **every** threat below against the discovered surface. Each item is either **modeled**
(a row in the threat matrix) or **explicitly N/A** (one line in an "Out of scope" subsection
with the reason — e.g. "Svelte `{@html}` items: N/A, no `{@html}` usage found"). Never silently
drop an item. Add stack-specific threats you discover that are not listed — this catalog is the
floor, not the ceiling. Tag each modeled row with its **OWASP Top 10:2021** code (A01–A10) and
its **CWE** (CWE-79/352/942/1021/601/1004/693/444).
**A. Reflected & request-borne XSS (A03 · CWE-79) — SecureNow's home turf**
1. Reflected XSS — request param/header echoed unescaped into HTML body context
2. Reflected XSS into an HTML **attribute** context (breaking out of `"…"` / unquoted attr)
3. Reflected XSS into a **JavaScript** context (inline `<script>` / event handler / JSON-in-HTML)
4. Reflected XSS into a **URL/href/src** context (`javascript:`, `data:text/html`)
5. Reflected XSS into a **CSS** / `style=` context (`expression()`, `url()`)
6. Reflected XSS via a **header** reflected into HTML (Referer, User-Agent, custom header)
7. Reflected-download / MIME-sniff XSS — user content served inline with sniffable type
**B. Stored / persistent XSS (A03 · CWE-79)**
8. Stored XSS in user profile fields (name, bio, website, status)
9. Stored XSS in user-generated content (comments, reviews, messages, posts, tickets)
10. Stored XSS via filename / metadata / uploaded-content rendered in the UI
11. Stored XSS in admin-viewed fields (support console rendering raw user input → admin ATO)
12. Stored XSS via unsanitized **markdown / rich-text / WYSIWYG / HTML-email** rendering
13. Stored XSS via SVG / XML / polyglot served from the app origin
**C. DOM-based & mutation XSS (A03 · CWE-79)**
14. DOM XSS — `location`/`hash`/`search`/`referrer`/`window.name` flowing to `innerHTML`/`document.write`
15. DOM XSS via `eval`/`new Function`/`setTimeout(string)` on tainted input
16. DOM XSS via dangerous attribute sink (`setAttribute('href'|'srcdoc'|'onload', tainted)`)
17. Framework escape-hatch XSS — `dangerouslySetInnerHTML` / `v-html` / `{@html}` / `[innerHTML]` / `bypassSecurityTrust*`
18. Mutation XSS (mXSS) — sanitizer output re-parsed by the browser into active markup
19. Client-side template-injection / expression-context sink (AngularJS `{{}}`, client templating)
20. DOM-clobbering / prototype-pollution gadget enabling script execution
**D. CSRF — cross-site request forgery (A01 · CWE-352)**
21. CSRF on a state-changing POST/PUT/PATCH/DELETE with **no** anti-CSRF token
22. **GET that mutates** (state change via a cacheable/embeddable GET → trivial CSRF)
23. Weak/guessable/static CSRF token, or token not bound to the session
24. CSRF token present but **not verified** server-side (accept-if-present bypass)
25. `SameSite` gap — session cookie `SameSite=None`/missing → cross-site auto-send
26. **JSON-CSRF** / simple-request CSRF (`text/plain` or form content-type accepted for mutations)
27. Login CSRF (attacker logs victim into attacker's account) / logout CSRF
28. CSRF via method override (`X-HTTP-Method-Override`/`_method`) reaching a protected verb
**E. CORS misconfiguration (A05 · CWE-942)**
29. **Reflected `Origin` + `Access-Control-Allow-Credentials: true`** (any site reads responses)
30. `Access-Control-Allow-Origin: *` **with** credentials (or `*` on sensitive authed data)
31. `null` origin accepted (sandboxed iframe / `data:`/`file:` bypass)
32. Weak origin-match regex (`endsWith`/`startsWith`/unescaped `.`/missing anchor → subdomain/suffix bypass)
33. Over-broad `Access-Control-Allow-Methods` / `…-Headers` / pre-flight always-200
34. Trusting all subdomains where a subdomain is attacker-controllable (takeover/wildcard)
35. Missing `Vary: Origin` causing a cached permissive CORS response to leak cross-user
**F. Clickjacking / UI redress (A05 · CWE-1021)**
36. No `X-Frame-Options` / `frame-ancestors` → page framable for clickjacking
37. `frame-ancestors`/XFO too permissive (`ALLOWALL`, wildcard, broad allowlist)
38. Drag-and-drop / paste / overlay redress on a sensitive action framed by an attacker
**G. Security-header posture (A05 · CWE-693)**
39. Missing `Content-Security-Policy` (no defense-in-depth against XSS)
40. Weak CSP — `unsafe-inline` / `unsafe-eval` / wildcard sources / no nonce-or-hash
41. CSP in `report-only` only (never enforcing) — false sense of protection
42. Missing `Strict-Transport-Security` (HSTS) → SSL-strip / cookie over HTTP
43. Missing `X-Content-Type-Options: nosniff` → MIME-sniff XSS
44. Missing/weak `Referrer-Policy` → token/PII leak in `Referer` to third parties
45. Missing `Cross-Origin-Opener-Policy` / `Cross-Origin-Resource-Policy` (XS-leaks / Spectre isolation)
46. Missing `Permissions-Policy` (unneeded powerful features left enabled)
**H. Cross-origin script & frame messaging (A05/A08 · CWE-346/CWE-942)**
47. `postMessage` handler with no/weak `event.origin` check trusting `event.data` into a sink
48. `postMessage` **send** to `targetOrigin: '*'` leaking data to any embedder
49. `window.opener` / `target=_blank` reverse-tabnabbing (no `rel=noopener`)
50. `iframe` embedding untrusted third-party content with excessive `sandbox`/`allow` perms
51. Origin check via `indexOf`/`includes`/substring on `event.origin` (bypassable)
**I. Open redirect & navigation (A01 · CWE-601)**
52. Open redirect from `next`/`returnTo`/`redirect`/`url`/`callback` param (no allowlist)
53. Open redirect enabling **token/credential leak** (carries auth/code to attacker host)
54. Protocol-relative / `javascript:` / `data:` redirect target accepted
55. Post-login / post-logout / OAuth `redirect_uri` reflection (defer OAuth deep model to auth)
**J. Cookie scoping & flags (A05 · CWE-1004/CWE-614/CWE-1275)**
56. Session/auth cookie missing `HttpOnly` (readable by XSS)
57. Cookie missing `Secure` (sent over HTTP) / `SameSite=None` without `Secure`
58. Over-broad cookie `Domain` (parent domain → sibling-subdomain theft)
59. Missing `__Host-`/`__Secure-` prefix on session cookies (allows overwrite/scoping attacks)
**K. Content-type, MIME & parser confusion (A05 · CWE-444/CWE-79)**
60. MIME sniffing of user content into `text/html` (missing `nosniff` + wrong type)
61. User-controlled `Content-Type` / charset trick (UTF-7, BOM) bypassing escaping
62. Content sniffed/served inline that should be `attachment` (download XSS)
**L. Negative-space & WAF/evasion encodings (A03/A05 · CWE-79/CWE-942)**
63. Encoding/normalization bypass of the signature rule (double/URL/HTML-entity/unicode/`%00`/case)
64. Payload split across params / smuggled in a header / chunked to evade pattern match
65. Direct-origin access bypassing the CDN/WAF (hitting origin IP, headers stripped)
66. Mutation/encoding mXSS payloads that pass a sanitizer but execute in the browser
**M. Observable abuse (what telemetry actually catches — the workhorse rules)**
67. XSS exploit-signature match in a request (reflected payload in URL/body/header) → instant block
68. High-rate XSS/CSRF/CORS **probe fuzzing** from one IP (many payload variants, many 4xx)
69. CORS-preflight (OPTIONS) anomaly — one IP sending many cross-origin probes / unusual Origins
70. Spike of requests carrying `<script>`/`onerror=`/`javascript:`/encoded payload markers
71. One IP hitting many distinct redirect/`next=`/`returnTo=` targets (open-redirect probing)
72. Stored-payload submission burst to a UGC write endpoint (mass comment/profile XSS seeding)
**N. App-emitted client-side signals (need instrumentation — see 4a)**
73. CSP violation reports ingested as events (`security.csp.violation`) → live XSS attempt signal
74. App-side CSRF rejection (`security.csrf.rejected`) → forgery attempts in flight
75. App-side CORS rejection (`security.cors.rejected`) → unauthorized cross-origin reads attempted
76. App-side sanitizer strip / dangerous-input rejection (`security.xss.blocked`) → stored-XSS attempts
77. App-side open-redirect block (`security.redirect.blocked`) → redirect abuse attempts
78. App-side `postMessage` origin rejection (`security.postmessage.rejected`) → cross-frame probing
**O. Deferred — modeled in sibling reports (reference, do not re-derive)**
79. Server-side injection — SQLi / RCE / SSTI / NoSQL / command (A03) → [../06-injection/](../06-injection/)
80. Session/cookie **issuance**, theft, fixation, revocation, token validity (A07) → [../01-authentication/](../01-authentication/)
81. Third-party script trust, CSP/SRI supply-chain, compromised CDN/npm (A06/A08) → [../05-client-side-supply-chain/](../05-client-side-supply-chain/)
82. **Authorization impact** of a successful CSRF / forged state change (A01 BOLA/BFLA) → [../02-authorization/](../02-authorization/)
> For 79–82, add **one** matrix row each marked *"deferred — see linked model"*, and only note
> the SecureNow traffic-observable symptom here (e.g. SQLi-signature hits → injection model;
> session-cookie theft via the XSS this model finds → auth model). The full detection/mitigation
> lives in the linked reports. **Item 80 is the natural consumer of item 56**: an XSS that steals
> a non-`HttpOnly` session cookie is modeled here as the *flaw* and there as the *impact*.
---
## Phase 3 — Audit the code (findings only — do not fix)
For **each** modeled threat that maps to real code, locate the responsible code and record a
**finding** for the report's "Code-level findings" section. A finding is:
- **Location** — `file:line` (clickable), the component/route/handler/middleware/template name.
- **Pattern** — quote the 1–8 relevant lines. State the missing control precisely (e.g.
"`dangerouslySetInnerHTML={{__html: comment.body}}` with no DOMPurify → stored XSS";
"`res.send('<h1>Hi '+req.query.name+'</h1>')` → reflected XSS, HTML context";
"`cors({ origin: true, credentials: true })` reflects any Origin with credentials";
"`app.post('/transfer')` with no CSRF token and `SameSite` unset"; "`res.redirect(req.query.next)`
with no allowlist"; "no `helmet()` / no `Content-Security-Policy` set anywhere";
"`window.addEventListener('message', e => render(e.data))` with no `e.origin` check").
- **Why exploitable** — the concrete attacker action and what they achieve (the exact payload /
the attacker-hosted HTML form / the malicious page that frames or reads the target).
- **Severity** — critical / high / medium / low (impact × reachability; stored XSS hitting an
admin console = critical; missing header on a static page = low).
- **Recommended fix (described, not applied)** — the specific change: e.g. "contextually
escape on output / render as text, not HTML"; "sanitize markdown HTML with DOMPurify and an
allowlist, strip `javascript:`/`data:` and event-handler attrs"; "remove the
`dangerouslySetInnerHTML`, render `{comment.body}`"; "add a synchronizer CSRF token bound to
the session, verify constant-time on every mutating route"; "set `SameSite=Lax` (or `Strict`)
on session cookies, `Secure`, `HttpOnly`, `__Host-` prefix"; "replace `origin: true` with an
explicit origin allowlist; drop `credentials` on public routes"; "anchor the origin regex
(`^https://app\.example\.com$`)"; "add `helmet()` with an enforcing nonce-based CSP, HSTS,
`nosniff`, `frame-ancestors 'none'`, `Referrer-Policy: no-referrer`"; "validate `next` against
a same-origin path allowlist"; "check `event.origin === 'https://trusted.example'` and
validate `event.data` shape"; "add `rel='noopener noreferrer'` to all `target=_blank` links";
"serve untrusted downloads with `Content-Type: application/octet-stream`,
`X-Content-Type-Options: nosniff`, `Content-Disposition: attachment`". Reference the secure
pattern, not a code diff. **You must not edit the codebase.**
If a control exists and is correct (framework auto-escaping intact, DOMPurify on all markdown,
strict CSP with nonces, CSRF tokens enforced, CORS locked to an allowlist, `frame-ancestors 'none'`),
note it as a **strength** — the posture must be honest. Absence of a control where the surface
exists is itself a finding ("no CSP on any route"; "no CSRF protection on any mutating route").
Look specifically for:
**XSS sink flaws** — every `innerHTML`/`outerHTML`/`insertAdjacentHTML`/`document.write`/
`dangerouslySetInnerHTML`/`v-html`/`{@html}`/`[innerHTML]`/`bypassSecurityTrust*`/jQuery
`.html()`/`eval`/`new Function`/`setTimeout(string)` reachable from a tainted source;
server templates using raw/unescaped output (`{{{ }}}`, `| safe`, `| raw`, `html_safe`,
`@Html.Raw`, `v-pre`); markdown rendered without a sanitizer or with an over-broad allowlist;
SVG/HTML upload served from the app origin. *Recommended fixes must mention* contextual output
encoding, text-not-HTML rendering, DOMPurify/sanitize-html with strict allowlists, Trusted
Types, and an enforcing CSP as defense-in-depth.
**CSRF flaws** — mutating routes with no synchronizer/double-submit token; tokens not bound to
the session or not verified; non-constant-time comparison; `SameSite` unset/`None` without a
header-based defense; GET handlers that mutate; mutations accepting `text/plain`/form
content-types (CORS-simple-request CSRF); SPA relying only on a custom header without verifying
it. *Recommended fixes must mention* session-bound synchronizer tokens, constant-time
comparison, `SameSite=Lax/Strict`, restricting mutations to `application/json` + an
`X-Requested-With`/custom-header check, origin/referer validation, and making GETs side-effect-free.
**CORS flaws** — `origin: true` / reflected Origin with `credentials: true`; `*` with
credentials; `null` accepted; `endsWith`/`startsWith`/substring/unescaped-dot origin matching;
over-broad methods/headers; missing `Vary: Origin`. *Recommended fixes must mention* an explicit
origin allowlist, anchored exact-match (not regex substring), never combining `*` with
credentials, dropping credentials on public endpoints, and `Vary: Origin`.
**Clickjacking & header flaws** — no `helmet`/equivalent; missing or weak CSP
(`unsafe-inline`/`unsafe-eval`/wildcard); CSP report-only only; missing HSTS / `nosniff` /
`X-Frame-Options` / `frame-ancestors` / `Referrer-Policy` / COOP/COEP/CORP / `Permissions-Policy`;
headers set on some routes but not the API/error/upload routes. *Recommended fixes must mention*
a single centralized security-header middleware, nonce/hash-based enforcing CSP,
`frame-ancestors 'none'` (or an allowlist), HSTS with `includeSubDomains; preload`, `nosniff`,
and a restrictive `Referrer-Policy`.
**postMessage / opener / redirect flaws** — message handlers without an exact `event.origin`
allowlist that trust `event.data` into a sink; `postMessage(..., '*')` sends;
`indexOf`/`includes` origin checks; `target=_blank`/`window.open` without `noopener`; redirects
built from request input without an allowlist; protocol-relative/`javascript:`/`data:` targets
accepted. *Recommended fixes must mention* exact-origin equality checks, validating message
shape, `targetOrigin` set to the specific origin, `rel="noopener noreferrer"`, and same-origin
path allowlists for redirects.
**Cookie & content-type flaws** — session/auth cookies missing `HttpOnly`/`Secure`/`SameSite`;
over-broad `Domain`; no `__Host-`/`__Secure-` prefix; user content served inline with a
sniffable/wrong `Content-Type` and no `nosniff`/`attachment`. *Recommended fixes must mention*
`HttpOnly; Secure; SameSite=Lax`, host-scoped cookies, the `__Host-` prefix, correct
`Content-Type`, `nosniff`, and `Content-Disposition: attachment` for untrusted downloads.
---
## Phase 4 — Map every modeled threat to SecureNow detection + mitigation
Classify each threat with exactly one coverage badge. **This domain is mostly app/config fix**,
so most rows are 🟡 (edge containment + primary app fix) or 🔴 (pure app fix). Be honest — do
not inflate to 🟢.
- 🟢 **COVERED** — detectable + mitigable with SecureNow today on telemetry already flowing.
In this domain that is essentially **request-borne XSS via the system XSS signature rule +
`instant.block`** (reflected payload in a URL/body/header is blocked synchronously, ~2.6s),
plus the traffic-based **probe/fuzz/preflight-anomaly** rules. *Native ceiling here is
LOW–MEDIUM.*
- 🟡 **PARTIAL** — SecureNow can **contain the abuser at the edge** (block the IP fuzzing
payloads, rate-limit/challenge a probe flood, surface a posture finding) **but the root cause
is an app/config fix** (CSRF token, `SameSite`, CSP, CORS allowlist, output encoding,
`noopener`, redirect allowlist). Also: detections that only work **after** the customer adds a
`securenow/events` `track()` (`security.csp.violation`, `security.csrf.rejected`, etc.). Pair
the containment with the app fix on every such row.
- 🔴 **GAP** — SecureNow cannot detect or mitigate this at the edge today (DOM-only XSS that
never touches the server; a missing CSP/header that emits no abusive traffic until exploited;
a `postMessage` origin bug entirely in the browser; a cookie missing `HttpOnly`). **Still
include it**: give the app/config-level fix, then add the line *"Requires SecureNow team —
contact your SecureNow account contact (or in-dashboard support) to request support for this
threat."* Collect all gaps in the report's "Known gaps & SecureNow feature requests" section.
> **Be brutally honest about edge-detectable vs app-fix.** SecureNow sees **server-bound
> traffic** and **events**. A **reflected** XSS payload travels through the request → the XSS
> signature can catch and `instant.block` it (🟢). A **DOM-only** XSS where `location.hash`
> flows to `innerHTML` **never reaches the server** → SecureNow is blind until the app emits a
> CSP-violation event (🟡/🔴). **CSRF** is a *browser-driven legit-looking request*; SecureNow
> can detect forgery *attempts* only if the app emits `security.csrf.rejected`, and the real
> fix is a token + `SameSite` (🟡, app-fix primary). A **misconfigured CORS header** or a
> **missing CSP** is a *response posture* problem SecureNow can flag as a finding but cannot
> rewrite — it's an app/config fix (🔴/🟡). Pair the control with the app fix on every such row.
> A flaw that emits no request traffic and no event is a 🔴 until the app emits the event in
> Phase 3's recommended fix.
Use **only** the SecureNow building blocks below. Never invent CLI flags, event names, or SQL
columns.
### 4a. Instrumentation (what client-side detections feed on)
Once the app runs under `securenow run` / `securenow/register` / `securenow init`, **HTTP
traffic is captured automatically** — methods, paths, **query strings and bodies** (subject to
redaction), client IPs, response status, the `Origin`/`Referer`/`User-Agent` request headers.
**Request-borne XSS, CORS-preflight floods, and open-redirect probing need no events** — they
are visible in traffic and handled by the signature rule + the SQL rules below.
For **client-side-only** signals that traffic can't see (DOM XSS, CSP violations, app-side
CSRF/CORS/redirect rejections), add `securenow/events` `track()` at the enforcement point
(**never throws**):
```js
const { track } = require('securenow/events');
// A CSP violation report arrived at your /csp-report endpoint (live XSS / injection attempt):
track('security.csp.violation', { ip, attributes: { route: '/dashboard', directive: 'script-src', blocked_uri: 'inline', disposition: 'enforce' } });
// Your server rejected a request for a missing/invalid CSRF token (forgery attempt):
track('security.csrf.rejected', { userId, ip, attributes: { route: '/api/transfer', reason: 'missing_token|invalid_token|origin_mismatch', method: 'POST' } });
// Your CORS middleware refused a cross-origin request (unauthorized read attempt):
track('security.cors.rejected', { ip, attributes: { route: '/api/me', origin: 'https://evil.example', reason: 'origin_not_allowed' } });
// Your sanitizer stripped dangerous markup / you rejected dangerous input (stored-XSS attempt):
track('security.xss.blocked', { userId, ip, attributes: { route: '/api/comment', sink: 'markdown|html|svg', reason: 'script_tag|event_handler|js_uri' } });
// Your redirect guard blocked an off-allowlist target (open-redirect / token-leak attempt):
track('security.redirect.blocked', { ip, attributes: { route: '/login', target_host: 'evil.example', reason: 'not_allowlisted|protocol_relative|js_uri' } });
// A postMessage handler rejected a message from an untrusted origin (cross-frame probing):
track('security.postmessage.rejected', { ip, attributes: { route: '/embed', origin: 'https://evil.example', reason: 'origin_not_allowed' } });
```
> Hash or omit any PII/secret before it becomes an attribute value (session tokens, the raw
> reflected payload if it contains a victim's data, emails) — see the Phase 1 **telemetry
> privacy & redaction** check. Attributes feed detection; they must not become a new leak path
> (a stored XSS payload echoed verbatim into the dashboard is a self-inflicted vuln).
Recommended client-side event taxonomy — rules match these **exact strings**:
| Event | Emit when |
|---|---|
| `security.csp.violation` | a CSP `report-uri`/`report-to` violation report is received |
| `security.csrf.rejected` | a request is rejected for a missing/invalid CSRF token or origin mismatch |
| `security.cors.rejected` | a cross-origin request is refused by the CORS policy |
| `security.xss.blocked` | a sanitizer strips dangerous markup or dangerous input is rejected |
| `security.redirect.blocked` | a redirect target fails the same-origin/allowlist check |
| `security.postmessage.rejected` | a `postMessage` handler rejects an untrusted `event.origin` |
Custom `attributes` become queryable as `attributes_string['<key>']` (e.g.
`attributes_string['directive']`, `attributes_string['origin']`). Ingest enriches every IP with
**ASN/org** (`client.asn`, `client.as_org`) — enabling botnet/datacenter-origin detection of
probe floods with no extra code.
### 4b. Detection rules — SQL conventions
Two query shapes. Both **must** keep the tenant scope and **must** select an `ip` column
(per-IP aggregation is what remediation/auto-block keys on). **The tenant-scope column differs
by table** — using the wrong one fails with `UNKNOWN_IDENTIFIER`:
- **logs/events** (`signoz_logs.distributed_logs_v2`) → `resources_string['service.name'] IN (__USER_APP_KEYS__)`
- **traces/HTTP** (`signoz_traces.distributed_signoz_index_v3`) → `` `resource_string_service$$name` IN (__USER_APP_KEYS__) ``
When grouping by `ip`, add `HAVING ip != '' AND …` so rows with no client IP don't aggregate
into an empty-key bucket. Traffic columns proven available: `response_status_code`, `kind`
(server span = 2), `ts_bucket_start`, `attributes_string['http.target']`, the `client_ip`
coalesce below. Confirm any other column (`http.method`, request header attributes like
`attributes_string['http.request.header.origin']`) with a `--mode dry_run` before relying on
it; OTEL SDK versions vary in which request headers/bodies they capture.
> **Request-borne XSS itself is handled by the system XSS signature rule + `instant.block`, not
> by hand-written pattern SQL** (see the injection note below). The SQL rules here detect the
> *abuse pattern around it*: payload-probe fuzzing, CORS-preflight anomalies, and open-redirect
> probing — none of which the signature rule scores on its own.
**Traffic-based — XSS/CSRF/CORS probe fuzzing (one IP, many client errors across many paths):**
```sql
WITH coalesce(nullIf(attributes_string['http.client_ip'], ''), nullIf(attributes_string['net.peer.ip'], ''), nullIf(attributes_string['network.peer.address'], '')) AS client_ip
SELECT client_ip AS ip,
uniqExact(attributes_string['http.target']) AS distinct_paths,
countIf(response_status_code IN ('400','403','404','422')) AS client_errors,
count() AS total
FROM signoz_traces.distributed_signoz_index_v3
WHERE `resource_string_service$$name` IN (__USER_APP_KEYS__)
AND timestamp >= now64(9) - INTERVAL 15 MINUTE
AND ts_bucket_start >= toUInt64(toUnixTimestamp(now() - INTERVAL 15 MINUTE)) - 1800
AND kind = 2
GROUP BY ip
HAVING ip != '' AND distinct_paths >= 25 AND client_errors >= 40
```
**Traffic-based — payload-marker spike (reflected XSS / open-redirect / `javascript:` in the URL):**
```sql
WITH coalesce(nullIf(attributes_string['http.client_ip'], ''), nullIf(attributes_string['net.peer.ip'], ''), nullIf(attributes_string['network.peer.address'], '')) AS client_ip
SELECT client_ip AS ip,
count() AS payload_hits,
uniqExact(attributes_string['http.target']) AS distinct_targets
FROM signoz_traces.distributed_signoz_index_v3
WHERE `resource_string_service$$name` IN (__USER_APP_KEYS__)
AND timestamp >= now64(9) - INTERVAL 10 MINUTE
AND ts_bucket_start >= toUInt64(toUnixTimestamp(now() - INTERVAL 10 MINUTE)) - 1800
AND kind = 2
AND (positionCaseInsensitive(attributes_string['http.target'], '<script') > 0
OR positionCaseInsensitive(attributes_string['http.target'], 'onerror=') > 0
OR positionCaseInsensitive(attributes_string['http.target'], 'javascript:') > 0
OR positionCaseInsensitive(attributes_string['http.target'], '%3cscript') > 0
OR positionCaseInsensitive(attributes_string['http.target'], 'returnto=http') > 0
OR positionCaseInsensitive(attributes_string['http.target'], 'next=http') > 0)
GROUP BY ip
HAVING ip != '' AND payload_hits >= 5
```
> This SQL is a **breadth/volume amplifier and forensic aid**, not the primary XSS control —
> the system XSS **signature rule + `instant.block`** is. Use this rule to catch *open-redirect
> probing* and *encoded-payload fuzzing* that round-trips the URL, and to auto-block a source
> spraying variants. It will under-match deliberately obfuscated payloads — do not present it as
> full XSS coverage; cite the signature rule for that.
**Events-based — CSP violation reports (DOM/reflected XSS attempt live, query the logs table):**
```sql
SELECT
attributes_string['http.client_ip'] AS ip,
attributes_string['directive'] AS directive,
attributes_string['blocked_uri'] AS blocked_uri,
count() AS violations
FROM signoz_logs.distributed_logs_v2
WHERE resources_string['service.name'] IN (__USER_APP_KEYS__)
AND attributes_string['event.type'] = 'security.csp.violation'
AND attributes_string['disposition'] = 'enforce'
AND timestamp >= now() - INTERVAL 15 MINUTE
GROUP BY ip, directive, blocked_uri
HAVING ip != '' AND violations >= 3
```
**Events-based — CSRF / CORS / redirect / postMessage rejection burst (forgery attempts):**
```sql
SELECT
attributes_string['http.client_ip'] AS ip,
attributes_string['event.type'] AS signal,
attributes_string['route'] AS route,
count() AS attempts
FROM signoz_logs.distributed_logs_v2
WHERE resources_string['service.name'] IN (__USER_APP_KEYS__)
AND attributes_string['event.type'] IN ('security.csrf.rejected','security.cors.rejected','security.redirect.blocked','security.postmessage.rejected')
AND timestamp >= now() - INTERVAL 15 MINUTE
GROUP BY ip, signal, route
HAVING ip != '' AND attempts >= 10
```
The remaining catalog-N events follow the **same shape** — swap the `event.type` filter and the
threshold: `security.xss.blocked` (≥5/15m → stored-XSS seeding burst, auto-block candidate),
`security.csp.violation` with `disposition='report'` (≥1 → notify-only, route to the CSP-tuning
runbook, do **not** auto-block — report-only is for tuning, not enforcement).
**Request-borne XSS (catalog A, and the symptom of B/C that round-trips) — use the SecureNow
system signature rule, don't write SQL.** Reflected XSS / `javascript:` / event-handler / known
mXSS-encoding detection ships as a **system signature rule** with synchronous **`instant.block`**
(blocks a matching request in ~2.6s on ingest). Confirm it is present and enabled for this app
via `securenow alerts rules --json` (look for the XSS/exploit signature rule); enable
`instant.block` rather than authoring duplicate pattern SQL.
Useful attributes/columns: `event.type`, `http.client_ip`, `http.target`,
`response_status_code`, `kind`, `client.asn`, `client.as_org`, and your client-side attributes
(`route`, `directive`, `blocked_uri`, `origin`, `target_host`, `reason`, `sink`).
#### Emit every rule as a ready-to-copy command unit
Each detection becomes a **complete, copyable unit** — never a fragment. For each rule emit, in
order: (1) the SQL, with a first comment line saving it to `rules/<name>.sql`; (2) a line/block
saving that SQL to `rules/<name>.sql`; (3) the full `securenow alerts rules create …` command
referencing `--sql @rules/<name>.sql`; (4) the dry-run test. In Markdown each is its own fenced
block so it copies cleanly. The **exact flags must match `securenow alerts rules --help`** from
Phase 0.5 (`--name`/`--sql`/`--apps`/`--severity`/`--schedule`/`--nlp`) — do not invent flags.
Note pre-existing/system rules (incl. the system XSS signature rule + `instant.block`) instead of
duplicating them with hand-written SQL. Example unit:
```sql
-- rules/xss-probe-fuzz.sql
WITH coalesce(nullIf(attributes_string['http.client_ip'], ''), nullIf(attributes_string['net.peer.ip'], ''), nullIf(attributes_string['network.peer.address'], '')) AS client_ip
SELECT client_ip AS ip,
uniqExact(attributes_string['http.target']) AS distinct_paths,
countIf(response_status_code IN ('400','403','404','422')) AS client_errors,
count() AS total
FROM signoz_traces.distributed_signoz_index_v3
WHERE `resource_string_service$$name` IN (__USER_APP_KEYS__)
AND timestamp >= now64(9) - INTERVAL 15 MINUTE
AND ts_bucket_start >= toUInt64(toUnixTimestamp(now() - INTERVAL 15 MINUTE)) - 1800
AND kind = 2
GROUP BY ip
HAVING ip != '' AND distinct_paths >= 25 AND client_errors >= 40
```
```bash
securenow alerts rules create \
--name "XSS/CSRF/CORS: probe fuzzing (single IP)" \
--sql @rules/xss-probe-fuzz.sql \
--apps <APP_KEY> \
--severity high \
--schedule "*/5 * * * *" \
--nlp "single IP hitting 25+ distinct paths with 40+ client errors in 15 minutes"
securenow alerts rules test <RULE_ID> --mode dry_run --wait # validate before it runs live
```
#### Test mode for false-positive-prone rules — ship FP-prone rules detect-only first
Alert rules have a lifecycle **mode**: `test` = **detect-only, NO mitigation** vs `prod` = full
(mitigation / auto-action armed) — plus a **status** (`Active | Disabled | Paused`). Manage with:
```bash
securenow alerts rules update <RULE_ID> --mode test # detect-only: fires notifications, takes NO action
# …observe real traffic for several days; tune the threshold; add securenow fp exclusions for any FPs…
securenow alerts rules update <RULE_ID> --mode prod # promote: arm the mitigation / auto-action
securenow alerts rules update <RULE_ID> --status Paused # or --enable / --disable / --pause shortcuts
```
**Rule of thumb:** any detection that can **false-positive** — heuristic thresholds (probe-fuzz /
payload-marker / CORS-preflight / open-redirect-probe counts), broad patterns, anomaly / volume
rules, anything tuned to YOUR traffic — must ship in **`--mode test` first**. Run it detect-only for
**3–7 days of real traffic**, review what it flags, raise/lower the threshold and add `securenow fp`
exclusions for legitimate hits (legit `<script>` in a search box, browser-extension CSP noise,
partner cross-origin reads), then `--mode prod` to arm mitigation. Only **high-precision** rules
(the request-borne XSS exploit-signature match, exact-match IoCs, known-bad ASN hits) may go
straight to `prod`. In the report, **tag each rule `test-first` or `prod-ready`** and say why.
(`securenow alerts rules test <id> --mode dry_run --wait` is the separate one-off *query*
validation — run it before either.) In this domain almost every SQL rule here (probe-fuzz,
payload-marker spike, CSP-violation, rejection-burst) is **`test-first`**; the system XSS signature
+ `instant.block` is the **`prod-ready`** exception.
### 4c. Mitigation commands (the only allowed remediation surface)
For client-side & cross-origin threats, SecureNow **contains the actor at the edge** (and
**synchronously blocks request-borne XSS**); the **app/config fix** removes the underlying
weakness. **On almost every row in this domain the app/config fix is the PRIMARY remediation** —
pair it explicitly. Once a threat is confirmed, **choose the narrowest effective mitigation(s)
from ALL of these** and combine them (e.g. rate-limit `/search` + block the worst fuzzer IPs +
challenge a NAT egress seeding stored XSS). Re-check every command/flag against the installed SDK
in Phase 0.5 (`securenow <cmd> --help`); annotate `# requires securenow >= <ver>` if absent.
Scope by **app / env / route / method / IP / duration** to avoid hitting real users.
| # | Mitigation | Command (ready-to-copy) | Use / scope |
|---|---|---|---|
| 1 | **Free firewall (network)** | `securenow firewall enable --app <APP_KEY> --env production` · `securenow run --firewall-only` · test `securenow firewall test-ip <ip> --path /x --method GET` | 500k+ known-bad IPs, hourly refresh; drop scanners/payload-fuzzers before the app. No app change. |
| 2 | **Exploit-signature instant block** | enable the `instant` config on the system SQLi/XSS/RCE signature rules (dashboard / MCP `securenow_alert_rule_instant_update`); custom rule → create with `--execution-mode instant` | synchronous ~2.6s block of the matching request (request-borne reflected XSS, catalog A). Don't duplicate pattern SQL. |
| 3 | **IP block — global** | `securenow blocklist add <ip> --app <APP_KEY> --env production --reason "..."` | confirmed-malicious payload fuzzer / scanner, all routes. |
| 4 | **IP block — scoped to route (+ method)** | `securenow blocklist add <ip> --route /comment* --mode prefix --method ALL --app <APP_KEY> --env production --reason "..."` (`--mode exact\|prefix\|regex`, `--method GET\|POST\|…\|ALL`) | block an IP only on the abused UGC/redirect path; least collateral. |
| 5 | **IP block — temporary / time-boxed** | `securenow blocklist add <ip> --duration 24h --reason "..."` (`30m`,`24h`,`7d`) · reverse `securenow blocklist unblock <id> --reason "..."` | auto-expiring containment; audit-preserving unblock. |
| 6 | **Rate limit — per IP** | `securenow ratelimit add <ip> --limit 100 --window 1m --duration 24h --reason "..."` | throttle one fuzzer across the app. |
| 7 | **Rate limit — per route (all clients, per-IP budget)** | `securenow ratelimit add --route /search --mode prefix --method GET --limit 60 --window 1m --key-by ip` | cap an abusable reflective/redirect endpoint for everyone, budgeted per IP. |
| 8 | **Rate limit — per route + IP** | `securenow ratelimit add <ip> --route /api/comment --mode exact --method POST --limit 5 --window 1m --duration 24h` · NL `securenow ratelimit from-text "rate limit /api/comment to 5/min for 24h" --yes` · test `securenow ratelimit test <ip> --path /api/comment --method POST` | precise throttle of one client seeding stored XSS on one route. |
| 9 | **CAPTCHA / proof-of-work challenge** | `securenow challenge add --route /comment --difficulty 16 --clearance 30m` (route-wide) **or** `securenow challenge add <ip> --route /search --difficulty 18 --clearance 30m` · test `securenow challenge test <ip> --path /comment --method POST` | stored-XSS seeding / CSRF-attempt bursts from **shared / NAT / CGNAT** egress — a human passes once, a script can't. Prefer over a hard block when real users share the IP. |
| 10 | **Auto-block (risk-scored)** | `securenow automation defaults --yes` (≥95→7d, 90–94→72h, 85–89→24h) · custom `securenow automation create --conditions '[...]' --actions '[...]'` · preview `securenow automation dry-run <id>` | hands-off blocking by risk score of repeat XSS-signature offenders; actions include block / rate_limit / requireCaptcha. |
| 11 | **Session revocation** | `securenow revoke …` (SDK `securenow/sessions` `guard()` / `isRevoked()`) | session theft via the stolen non-`HttpOnly` cookie an XSS reads — kill the stolen session, not the IP (defers to the auth model). |
| 12 | **Trusted IP (suppress)** | `securenow trusted add <ip> --label "Pentest box / partner scanner / monitor"` | stop false positives from known-good infra — suppresses detection **and** mitigation. NOT deny-by-default. |
| 13 | **Allowlist (deny-by-default)** | `securenow allowlist add <ip> --label "..." --reason "..."` ⚠️ once any entry exists, ONLY listed IPs reach the app | lockdown of an internal/admin-only surface. Never for a public app. |
| 14 | **False-positive exclusion** | `securenow fp create --conditions '[...]' --rule-scope this_rule --reason "..."` · `securenow fp mark <notification-id> <ip> --rule-scope this_rule` · preview `securenow fp dry-run --conditions '[...]'` | keep a noisy probe/CSP rule quiet without weakening it (legit `<script>` in a search box, browser-extension CSP noise). |
| 15 | **App / config / code fix (primary for root cause)** | *described in the Code-Findings report, never auto-applied* | the actual fix: contextual output encoding / DOMPurify, CSRF token + `SameSite`, CORS allowlist, enforcing CSP + `frame-ancestors` + HSTS + `nosniff`, `rel=noopener`, redirect allowlist, `HttpOnly`/`__Host-` cookies, Trusted Types. SecureNow contains; the fix removes. |
**Choosing per threat** — by **confidence**: exploit-signature/exact IoC (request-borne reflected
XSS payload) → instant-block or block; probable bot on shared egress (stored-XSS seeding, CSRF
bursts) → **challenge**; noisy/legit-mixed traffic (probe-fuzz, CSP-violation rules) → **rate-limit
(test-mode first)**; session compromise via a stolen non-`HttpOnly` cookie → **revoke** (auth
model); known-good noise (pentest box, browser-extension CSP) → **trusted / fp**. By **blast
radius**: always scope to the narrowest `route`/`method`/`IP`/`duration` that stops the abuse; on
NAT/CGNAT/shared IPs prefer challenge/rate-limit over a hard block. **Always pair an edge mitigation
with the app/config fix** (Code-Findings report) — for CSRF/CORS/headers/cookies/DOM-XSS the
app/config fix is the *primary* remediation and SecureNow only contains, except request-borne
reflected XSS where the signature instant-block is itself a real primary control. For **CSP
report-only** violations and posture findings (missing header, weak CORS), recommend **notify-only**
routed to the app-fix runbook — there is no IP to block, the fix is in code/config.
### 4d. Testing every detection and mitigation
Only test against apps/environments the user owns; prefer `--env local`/staging. For synthetic
source IPs use TEST-NET ranges (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`).
```bash
# Synthetic client-side events — exercise an events-based rule end to end (CSP violations):
for i in $(seq 1 5); do
securenow event send security.csp.violation --ip 203.0.113.50 \
--attrs route=/dashboard,directive=script-src,blocked_uri=inline,disposition=enforce,test=true
done
# Synthetic CSRF / CORS / redirect rejection burst:
for i in $(seq 1 12); do
securenow event send security.csrf.rejected --ip 203.0.113.51 \
--attrs route=/api/transfer,reason=missing_token,method=POST,test=true
done
securenow event send security.cors.rejected --ip 203.0.113.51 \
--attrs route=/api/me,origin=https://evil.example,reason=origin_not_allowed,test=true
# Synthetic stored-XSS seeding burst:
for i in $(seq 1 6); do
securenow event send security.xss.blocked --ip 203.0.113.52 \
--attrs route=/api/comment,sink=markdown,reason=script_tag,test=true
done
# Validate a rule query without waiting for the schedule:
securenow alerts rules test <RULE_ID> --mode dry_run --wait
# Traffic-based rules (probe fuzz / payload-marker spike) — generate spans, then check pipeline:
securenow test-span "threat-model.xss.smoke"
securenow forensics "requests containing <script> or javascript: by IP in the last hour" --env production
# Request-borne XSS signature + instant block — confirm a payload triggers the system rule (staging):
# send a request carrying a benign-but-matching marker (e.g. ?q=<script>1</script> or ?next=javascript:alert(1))
# to a STAGING URL, then verify the block fired:
securenow firewall test-ip 203.0.113.50 --app <APP_KEY> --env production
# Mitigation verification:
securenow ratelimit test 203.0.113.50 --path /search --method GET
securenow challenge test 203.0.113.50 --path /comment --method POST
# Confirm + clean up:
securenow notifications list --limit 10
securenow blocklist list # then: securenow blocklist unblock <id> --reason "threat-model test"
securenow challenge list # then: securenow challenge remove <id>
```
Every 🟢/🟡 threat row in the report must have a concrete test recipe (commands + expected
outcome: which rule fires, which notification appears, what the mitigation does). 🔴 rows have no
SecureNow test — state the manual verification (e.g. "frame the page in attacker HTML and confirm
it renders" / "send a cross-origin `fetch` with credentials and confirm the response is readable").
---
## Phase 5 — Write the FOUR deliverables (two tracks: Detection & Mitigation + Code Findings)
Write **four** files into `threat/04-xss-csrf-cors/` — two tracks, each Markdown + a
self-contained HTML page:
1. `xss-csrf-cors-detection-mitigation.md` + `.html` — the **operational runbook** (track A).
2. `xss-csrf-cors-code-findings.md` + `.html` — the **code audit** (track B).
The two tracks **cross-link**: the gaps/instrumentation rows in the detection report link to the
relevant code finding, and the app/config-fix rows in the code report link back to the
detection-report row they back. SecureNow-runnable detections/mitigations live in the **Detection
& Mitigation** report; code/config changes live in the **Code Findings** report; nothing
security-relevant is dropped.
### 5a. Detection & Mitigation report — sections (both `.md` and `.html`), in order
1. **Executive summary** — stats line (N threats modeled · N covered · N partial · N gaps ·
N rules to create · N mitigations), top 3 detectable client-side risks for this specific
stack, installed `securenow` version + app key + firewall state, one-paragraph posture
verdict, and a one-line OWASP Top 10:2021 coverage note (A03/A05 owned here; server-side
injection/session/supply-chain/authz deferred). **State plainly that native SecureNow
coverage here is LOW–MEDIUM** (request-borne XSS signature + edge containment).
2. **SDK & environment** — installed SDK version (from `node_modules/securenow`, Phase 0.5),
app key(s), environment, firewall state, existing rules/automations/challenge rules
(from Phase 0), and the system signature rules present (esp. the **XSS** signature rule).
3. **Threat → Detection → Mitigation matrix** — one row per modeled threat:
`# | Threat | OWASP | CWE | Coverage 🟢/🟡/🔴 | Detection rule | Signal (threshold+window) | Schedule | Sev | Mode (test-first/prod-ready) | Mitigation`.
Severity ∈ {critical, high, medium, low}. The **Mitigation cell must select specific, scoped
mitigation(s) from the Phase 4c toolbox** (by toolbox # / name, scoped to route/method/IP/
duration) — never a generic "block the IP." The **Mode cell tags each rule `test-first` or
`prod-ready`** per Phase 4b (FP-prone heuristic/volume rules → `test-first`; the request-borne
XSS signature + `instant.block` and exact-match IoCs → `prod-ready`). Every 🟡/🔴 row also names
the **app/config fix** in the Mitigation cell **and links to its row in the Code Findings
report**. Injection-class rows reference the **system XSS signature rule + `instant.block`**, not
duplicate SQL. Follow with the "Out of scope" N/A list and the deferred-to-sibling rows (79–82)
pointing to the sibling models.
4. **Detection rules to create** — each as the **ready-to-copy command unit** from Phase 4
(SQL → save to `rules/<name>.sql` → full `securenow alerts rules create …` → `--mode dry_run`
test). **Mark each rule `test-first` or `prod-ready`** (Phase 4b): a `test-first` rule ships in
`--mode test` (detect-only) and carries its `securenow alerts rules update <RULE_ID> --mode prod`
promotion step with a "promote after 3–7 days of observation + threshold tuning" note; a
`prod-ready` rule (the request-borne XSS signature, exact-match IoCs) arms immediately. Note
rules that already exist (from Phase 0, incl. the system XSS signature rule + `instant.block`)
instead of duplicating them.
5. **Instrumentation the detections need** — only the `track('security.*')` events the rules
above consume (CSP report endpoint, CSRF/CORS middleware, sanitizer, redirect guard,
`postMessage` handler), each as a copyable snippet; point to the **Code Findings** report for
*where* (file:line) to add them.
6. **Mitigation mechanisms** — render the **full Phase 4c mitigation toolbox table (all 15 rows:
firewall · exploit-signature instant-block · IP block [global / route+method / temporary] ·
rate-limit [per-IP / per-route / route+IP] · challenge · auto-block · session revocation ·
trusted · allowlist · fp · app-config fix)** + per-threat ready-to-copy mitigation command
(scoped to route/method/IP/duration) + reversibility. Make explicit that the **app/config fix
is the primary remediation** for CSRF/CORS/headers/cookies/DOM-XSS and the SecureNow control is
containment, except for request-borne reflected XSS where the signature instant-block is a real
primary control.
7. **Action plan (copy-paste, ordered)** — ① engage firewall + enable the **XSS signature
instant-block** (`prod-ready`), ② add the `security.*` event instrumentation where the browser
is blind (CSP report endpoint first), ③ create the probe/fuzz/CSP rules — **FP-prone rules
created in `--mode test` (detect-only)** with an explicit **"promote after N days"** step
(`securenow alerts rules update <RULE_ID> --mode prod` after 3–7 days of observation + threshold
tuning + `securenow fp` exclusions), ④ enable automations / challenge rules, ⑤ test, ⑥ verify in
dashboard, ⑦ **schedule the app/config-fix work from the Code Findings report — this is the bulk
of the remediation** (CSP, CSRF, CORS, `SameSite`, headers, sanitization). Real commands only,
`<APP_KEY>` already substituted.
8. **Testing & validation** — per-rule recipe (Phase 4d): `securenow event send …` /
`test-span` / dry-run + expected outcome + cleanup (TEST-NET IPs 192.0.2/198.51.100/203.0.113),
incl. the manual checks for 🔴 rows.
9. **Response runbooks** — per notification type: what fired, how to confirm a true positive,
the exact command to respond (copy), the exact command to reverse (copy), and — for posture
findings — the app/config change to file as a ticket (link to the Code Findings report).
10. **Known gaps & SecureNow feature requests** — every 🔴 threat: why it's not edge-coverable
today, the interim fix (link to the Code Findings report), and the "contact the SecureNow
team — contact your SecureNow account contact (or in-dashboard support)" line.
11. **Appendix** — resolved SDK/CLI version (from Phase 0.5), app key, environment, firewall
state, whether the XSS signature rule is enabled, rule IDs created, date, and a link to the
Code Findings report.
### 5b. Code Findings & Recommendations report — sections (both `.md` and `.html`), in order
State at the top: *"Findings only — no application code was modified."*
1. **Executive summary** — findings by severity (critical/high/medium/low), top 3 code risks for
this stack, one-paragraph posture verdict.
2. **Surface & inventory** — the Phase 1 inventory: XSS sink map (sink → source → context →
escaping?) + reflected/stored input map + CSRF posture table + CORS policy table +
security-header matrix + cookie-flags table + `postMessage`/opener/redirect/MIME lists +
telemetry redaction status.
3. **Threat catalog** — the exhaustive Phase 2 catalog (grouped A–O, each tagged OWASP/CWE,
modeled or explicit N/A), including the "Out of scope" N/A lines and the deferred-to-sibling
rows (79–82, linked).
4. **Code-level findings (audit)** — a table
`# | Location (file:line) | Threat | OWASP | CWE | Sev | Issue | Recommended fix`, each with
the quoted 1–8 line snippet, the HTML context (for XSS), and the described fix (never applied).
5. **Strengths** — controls already present and correct (framework auto-escaping intact,
DOMPurify on markdown, enforcing nonce-CSP, CSRF tokens enforced, CORS locked to an allowlist,
`frame-ancestors 'none'`) — the posture must be honest.
6. **App / config fixes (primary remediation)** — the config/code changes that remove the root
cause (described, not applied): contextual output encoding / DOMPurify, CSRF token +
`SameSite`, CORS allowlist, enforcing CSP + `frame-ancestors` + HSTS + `nosniff`,
`rel=noopener`, redirect allowlist, `HttpOnly`/`__Host-` cookies — each **linked to the
Detection & Mitigation matrix row it backs**.
7. **Instrumentation recommendations** — the `track('security.*')` calls to add and the exact
file:line to add them (the CSP `report-uri` endpoint, CSRF middleware, CORS middleware,
sanitizer, redirect guard, `postMessage` handler), so the detection rules light up.
8. **Appendix** — files reviewed, resolved SDK version (from Phase 0.5), date, and a link to the
Detection & Mitigation report.
### 5c. Self-contained HTML skeletons (offline; inline CSS + copy JS; no network)
Both HTML files share the `<head>` (brand tokens + copy-button styles) and the copy `<script>`
at the end of `<body>` below. **Change only the `<title>`, the sidebar subtitle, and the section
content** per track. Wrap EVERY command/SQL block as a `.cmd` (so it gets a Copy button) in the
**Detection & Mitigation** HTML; the Code-Findings HTML may omit copy buttons on prose but still
wraps any example/fix command in `.cmd`. Self-contained: inline CSS/JS, no CDN/fonts/network.
**Shared head + copy CSS + copy script (used by BOTH HTML files):**
```html
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title><!-- "Detection & Mitigation — XSS / CSRF / CORS — SecureNow" OR "Code Findings — XSS / CSRF / CORS — SecureNow" --></title>
<style>
:root{--bg:#0f1419;--panel:#161c24;--panel2:#1b2330;--border:#26303d;--txt:#dbe3ec;--muted:#8b97a7;
--accent:#3ea6ff;--accent2:#16c79a;--crit:#ff5c6c;--high:#ff9f43;--med:#f7c948;--low:#8b97a7;
--ok:#16c79a;--info:#3ea6ff;--rev:#b388ff;}
*{box-sizing:border-box}html{scroll-behavior:smooth}
body{margin:0;background:var(--bg);color:var(--txt);font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
a{color:var(--accent);text-decoration:none}
code{background:#0b0f14;border:1px solid var(--border);border-radius:5px;padding:.08em .4em;font:13px/1.4 ui-monospace,"SF Mono",Menlo,Consolas,monospace;color:#9fe0c0}
.wrap{display:grid;grid-template-columns:240px 1fr;max-width:1280px;margin:0 auto}
nav{position:sticky;top:0;align-self:start;height:100vh;overflow:auto;padding:28px 18px;border-right:1px solid var(--border);background:var(--panel)}
nav .brand{font-weight:700;font-size:15px;letter-spacing:.3px}nav .brand span{color:var(--accent)}
nav .sub{color:var(--muted);font-size:12px;margin-bottom:22px}
nav a{display:block;color:var(--muted);padding:7px 10px;border-radius:7px;font-size:13.5px}
nav a:hover{background:var(--panel2);color:var(--txt)}
main{padding:36px 40px 80px;min-width:0}
header.top h1{margin:0 0 6px;font-size:26px}header.top p{margin:0;color:var(--muted)}
.pill{display:inline-block;font-size:11px;font-weight:600;padding:3px 9px;border-radius:999px;border:1px solid var(--border);color:var(--muted);background:var(--panel)}
.stats{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin:26px 0 34px}
.stat{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:16px 18px}
.stat .n{font-size:26px;font-weight:700}.stat .l{color:var(--muted);font-size:12.5px;margin-top:2px}
section{margin:0 0 40px}
h2{font-size:18px;margin:0 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
h2 .num{color:var(--accent);font-weight:700;margin-right:8px}
table{width:100%;border-collapse:collapse;font-size:13.5px;background:var(--panel);border:1px solid var(--border);border-radius:12px;overflow:hidden}
th,td{text-align:left;padding:11px 13px;border-bottom:1px solid var(--border);vertical-align:top}
th{background:var(--panel2);color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.4px}
tr:last-child td{border-bottom:none}tr:hover td{background:#19212c}
.rid{font:12px ui-monospace,Menlo,Consolas,monospace;color:#7fd1ff;white-space:nowrap}
.b{display:inline-block;font-size:11px;font-weight:700;padding:2px 8px;border-radius:6px;white-space:nowrap}
.b.crit{background:rgba(255,92,108,.15);color:var(--crit);border:1px solid rgba(255,92,108,.35)}
.b.high{background:rgba(255,159,67,.13);color:var(--high);border:1px solid rgba(255,159,67,.32)}
.b.med{background:rgba(247,201,72,.13);color:var(--med);border:1px solid rgba(247,201,72,.32)}
.b.low{background:rgba(139,151,167,.13);color:var(--low);border:1px solid rgba(139,151,167,.32)}
.c{display:inline-block;font-size:11px;font-weight:700;padding:2px 8px;border-radius:6px;white-space:nowrap}
.c.cov{background:rgba(22,199,154,.13);color:var(--ok);border:1px solid rgba(22,199,154,.35)}
.c.part{background:rgba(247,201,72,.13);color:var(--med);border:1px solid rgba(247,201,72,.32)}
.c.gap{background:rgba(255,92,108,.15);color:var(--crit);border:1px solid rgba(255,92,108,.35)}
.owasp,.cwe{display:inline-block;font:11px ui-monospace,Menlo,Consolas,monospace;color:var(--accent);border:1px solid rgba(62,166,255,.3);border-radius:6px;padding:1px 6px;white-space:nowrap}
.cwe{color:var(--rev);border-color:rgba(179,136,255,.3)}
.m{display:inline-block;font-size:11px;font-weight:600;padding:2px 8px;border-radius:6px;border:1px solid var(--border)}
.m.block{color:var(--crit);border-color:rgba(255,92,108,.35)}.m.rate{color:var(--info);border-color:rgba(62,166,255,.35)}
.m.challenge{color:var(--accent2);border-color:rgba(22,199,154,.35)}.m.firewall{color:var(--ok);border-color:rgba(22,199,154,.35)}
.m.signature{color:var(--crit);border-color:rgba(255,92,108,.35)}.m.notify{color:var(--muted)}.m.appfix{color:var(--high);border-color:rgba(255,159,67,.35)}
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:18px 20px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
pre{background:#0b0f14;border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow:auto;font:13px ui-monospace,Menlo,Consolas,monospace;color:#cfe8da;margin:0}
.cmd{position:relative;margin:10px 0}
.copy{position:absolute;top:8px;right:8px;font:11px ui-monospace,Menlo,Consolas,monospace;color:var(--muted);background:var(--panel2);border:1px solid var(--border);border-radius:6px;padding:3px 9px;cursor:pointer}
.copy:hover{color:var(--txt);border-color:var(--accent)}.copy.done{color:var(--ok);border-color:var(--ok)}
.flow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:6px 0 14px}
.flow .step{background:var(--panel2);border:1px solid var(--border);border-radius:9px;padding:8px 12px;font-size:13px}.flow .arr{color:var(--accent);font-weight:700}
.note{border-left:3px solid var(--high);background:rgba(255,159,67,.06);padding:10px 14px;border-radius:0 8px 8px 0;color:#e7d3bd;font-size:13.5px;margin:10px 0}
footer{color:var(--muted);font-size:12px;border-top:1px solid var(--border);padding-top:18px;margin-top:30px}
@media(max-width:880px){.wrap{grid-template-columns:1fr}nav{display:none}.stats,.grid2{grid-template-columns:1fr 1fr}main{padding:24px 18px}}
</style></head>
<body>
<div class="wrap">
<nav>
<div class="brand">Secure<span>Now</span></div>
<div class="sub"><!-- "Detection & Mitigation · XSS / CSRF / CORS" OR "Code Findings · XSS / CSRF / CORS" --></div>
<!-- one <a href="#…"> per section of THIS track -->
</nav>
<main>
<header class="top"><h1><!-- report title --></h1>
<p><code><!-- app name / domain --></code> · <span class="pill">securenow <!-- installed version --></span></p></header>
<div class="stats"><!-- 5 .stat cards; numbers MUST equal the table/finding counts of THIS track --></div>
<!-- <section id="…"> blocks mirroring the Markdown sections of THIS track (5a or 5b) -->
<footer>Generated by the SecureNow XSS/CSRF/CORS threat-model prompt · <!-- date --> · securenow <!-- version --> · app <code><!-- APP_KEY --></code></footer>
</main>
</div>
<script>
document.querySelectorAll('.copy').forEach(function(b){b.addEventListener('click',function(){
var pre=b.parentElement.querySelector('pre'); if(!pre)return; var t=pre.innerText;
function done(){b.textContent='Copied';b.classList.add('done');setTimeout(function(){b.textContent='Copy';b.classList.remove('done');},1500);}
function fb(){var ta=document.createElement('textarea');ta.value=t;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.focus();ta.select();try{document.execCommand('copy');}catch(e){}document.body.removeChild(ta);done();}
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(t).then(done,fb);}else{fb();}
});});
</script>
</body></html>
```
**Track A — Detection & Mitigation `<body>`:** title `Detection & Mitigation — XSS / CSRF / CORS`,
sidebar subtitle `Detection & Mitigation · XSS / CSRF / CORS`, one `<section>` per 5a section
(1–11), and the 5 stat cards = threats modeled / covered / partial / gaps / rules to create.
Every SQL/command block uses the copyable wrapper:
```html
<div class="cmd"><button class="copy" type="button">Copy</button><pre>securenow alerts rules create \
--name "..." --sql @rules/<name>.sql --apps <APP_KEY> --severity high \
--schedule "*/5 * * * *" --nlp "..."</pre></div>
```
**Track B — Code Findings `<body>`:** title `Code Findings — XSS / CSRF / CORS`, sidebar
subtitle `Code Findings · XSS / CSRF / CORS`, one `<section>` per 5b section (1–8), and the 5
stat cards = findings critical / high / medium / low / total (or threats-modeled). Open with the
*"Findings only — no application code was modified."* note. Any example/fix command still wraps
in `.cmd`.
Badge usage: severity → `<span class="b crit|high|med|low">`, coverage →
`<span class="c cov|part|gap">COVERED|PARTIAL|GAP</span>`, OWASP tag →
`<span class="owasp">A03</span>`, **CWE tag → `<span class="cwe">CWE-79</span>`** (this domain
leans heavily on the `.cwe` badge — 79/352/942/1021/601/…), mitigation type →
`<span class="m firewall|signature|rate|challenge|block|notify|appfix">`, rule IDs →
`<span class="rid">`. Wrap every SQL/command block in `.cmd` with a Copy button (Detection HTML).
Stats numbers must equal the matrix/findings row counts of that track.
---
## Quality bar (the report is rejected if any of these fail)
- Every catalog item A1–O82 is either a matrix row or an explicit N/A line; each modeled row
carries its **OWASP Top 10:2021** tag (A01–A10 or "—") **and** its **CWE** (79/352/942/1021/601/…).
- Coverage badges are **honest**: native SecureNow contribution here is **LOW–MEDIUM** — only
request-borne reflected XSS (system signature + `instant.block`) and the traffic/event probe
rules are 🟢; CSRF tokens, `SameSite`, CSP, security headers, CORS allowlists, DOM-only XSS,
cookie flags, `postMessage`/`opener` are **app/config fixes** (🟡 with edge containment, or
🔴). No row is inflated to 🟢 that isn't.
- Every 🟡/🔴 row **pairs the edge containment with the primary app/config fix** in the
Mitigation cell — the root-cause fix is never omitted.
- The advanced/client-side signals (catalog N — CSP violation, CSRF/CORS/redirect/postMessage
rejection, sanitizer block) are each modeled or explicit N/A, with the matching `security.*`
event where the detection needs instrumentation.
- Server-side injection, session/credential security, third-party/CSP-supply-chain & SRI, and
CSRF authorization impact are **deferred** to the numbered sibling models (rows present,
linked to `../06-injection/`, `../01-authentication/`, `../05-client-side-supply-chain/`,
`../02-authorization/`, not re-derived).
- Every matrix row has a concrete signal (threshold + window), severity, and mitigation — no
"monitor for suspicious activity" filler.
- **Phase 0.5 ran**: the resolved installed `securenow` version appears in **both** reports'
appendix, and no command/flag/event/column is emitted that the installed SDK/CLI does not
expose (else it is annotated `# requires securenow >= <version>`).
- Every detection rule is a **complete copyable unit** (SQL → `rules/<name>.sql` → full
`securenow alerts rules create …` → `--mode dry_run` test); flags match `alerts rules --help`.
- **Four** files are written to `threat/04-xss-csrf-cors/` (`xss-csrf-cors-detection-mitigation`
`.md`+`.html`, `xss-csrf-cors-code-findings` `.md`+`.html`); the two tracks **cross-link**
(gaps/instrumentation rows → code findings, and app/config-fix rows → detection rows).
- The split is honest: SecureNow-runnable detections/mitigations live in the Detection &
Mitigation report; code/config changes live in the Code Findings report; nothing
security-relevant is dropped.
- Every code finding has a `file:line`, the quoted snippet, the HTML context (for XSS), and a
described fix — and **no application code was modified** (this is an audit).
- Every detection SQL keeps `__USER_APP_KEYS__` scoping (correct table column: `resources_string['service.name']`
for logs vs `` `resource_string_service$$name` `` for traces) and selects an `ip` column with
`HAVING ip != ''`; traffic queries keep the `client_ip` coalesce + `ts_bucket_start` + `kind = 2`
guards; every new rule is validated with `--mode dry_run`.
- Request-borne XSS coverage references the **system XSS signature rule + `instant.block`**, not
duplicate pattern SQL; the payload-marker SQL is presented as a volume/forensic amplifier, not
full XSS coverage.
- Only commands, flags, events, and SQL columns from this prompt's building blocks appear
(including `securenow challenge …`, `firewall`, and the `security.*` events).
- Every 🔴 gap appears in the gaps section with an interim app/config fix **and** the "contact
the SecureNow team" line; 🔴 rows give a manual verification step (no SecureNow test exists).
- The action plan runs top-to-bottom with `<APP_KEY>` substituted in, and explicitly schedules
the app/config-fix work (CSP/CSRF/CORS/headers/sanitization) as the bulk of the remediation.
- **Both HTML files are self-contained** (inline CSS/JS, no CDN/fonts/network), the stats cards
match the table/finding counts of their track, and **every command/SQL block in the Detection
& Mitigation HTML has a working Copy button**.
- A one-line summary is printed back to the user: per-track file paths, threat counts,
rules-to-create count, code findings by severity, gaps, OWASP/CWE coverage, and the resolved
installed `securenow` version.
- The Detection report's mitigation section presents the **full toolbox** (§6: firewall · instant-block ·
block [global / route / method / temporary] · rate-limit [IP / route / IP+route] · challenge · auto-block ·
revoke · trusted · allowlist · fp · app-fix), and **each modeled threat's matrix row selects specific,
scoped mitigation(s) from it** — never a generic "block the IP."
- **Every false-positive-prone rule is tagged `test-first`** and carries the `--mode test` → observe (3–7
days) → `--mode prod` promotion workflow; only high-precision rules are `prod-ready`. The action plan
creates the test-first rules in `--mode test` and has an explicit "promote after N days" step.
<!-- ════════════════ END OF PROMPT ════════════════ -->