CSPReporter — Content-Security-Policy Violation Triage
22 seeded CSP violations across 5 properties. Classifies each by directive (script-src, img-src, connect-src, frame-ancestors, …), risk class (XSS attempt / shadow IT / 3p drift / browser-noise / clickjacking probe / SRI mismatch / unsafe-eval / mixed-content), and recommended action with the actual directive fix.
What it is
The shape behind Sentry CSP, Report URI, Spectral — but pointed at the 4 reports that matter out of 14,200/day. Auto-classify, rank by risk, propose the fix.
What’s in it
- 22 violations across 5 properties (shop, marketing, app, support, press).
- 11 risk classes:
- xss-attempt —
javascript:alert(1), inline-with-onclick — investigate - shadow-it — Heap.io / OpenAI / Anthropic loading without DPA — block at egress
- 3p-drift — vendor-controlled CDN, unpinned versions — allowlist with SRI
- self-policy-gap — your own WSS endpoint blocked — fix the directive, not the page
- browser-noise — Grammarly, ad-blocker, chrome-extension:// — auto-filter at ingest
- partner-iframe — legit embeds — allowlist
- sri-mismatch — vendor changed file at the URL — investigate (supply-chain signal)
- unsafe-eval — eval() in admin export — refactor, do NOT add unsafe-eval
- mixed-content — http:// in https:// page — fix the link
- deprecated-vendor — old Zendesk script tag still loading — remove dead code
- clickjacking — frame-ancestors probe from attacker.example — investigate
- xss-attempt —
- Per-violation drilldown:
- Raw CSP report JSON payload
- Suggested directive change (or “do NOT change CSP, fix the page”)
- User-agent fingerprint distribution
- Recommended action with the why
- Cross-tool callbacks — shadow-IT class references EgressGate; SRI-mismatch references SbomScanner.
Why this shape
The standard problem with CSP reporting: 14k events a week, 4 of them matter, the rest is browser-extension noise. Most teams disable reporting after a week. CSPReporter prototypes the triage layer that separates the signal from the noise + maps each finding to the directive change (or refusal to change).
How it ships
Single HTML file, ~22KB. Zero dependencies. 22 violations × 11 classes × directive-fix templates in 220 lines of vanilla JavaScript.