CSP Academy

← The ten steps · Step 3 of 10 · 5 minutes

Read a violation report

The reports are the course material. Everything after this step is about acting on what they tell you.

What arrives

When a policy is violated the browser POSTs a small JSON document to your report-uri endpoint:

{
  "csp-report": {
    "document-uri": "https://example.com/checkout",
    "referrer": "",
    "violated-directive": "script-src-elem",
    "effective-directive": "script-src-elem",
    "original-policy": "default-src 'self'; report-uri /csp-reports",
    "disposition": "report",
    "blocked-uri": "https://widget.example.net/chat.js",
    "status-code": 200
  }
}

The four fields that matter

blocked-uri

What the page tried to load. This is the field you act on. It may also be one of a few keywords rather than a URL: inline (an inline script or style), eval (a string compiled as code), or data (a data: URL).

violated-directive / effective-directive

Which rule caught it. Note that browsers report the specific directive that applied — script-src-elem rather than script-src — even when your policy only names the broader one. That is not an error; it is telling you precisely which mechanism was involved.

document-uri

Which page it happened on. This is what turns a list of violations into a map of your own site, and it is usually the field that reveals the pages nobody remembered existed.

disposition

"report" means report-only mode — nothing was actually blocked. "enforce" means it was. Check this field before you panic about a spike.

Most of your reports will be noise

This surprises everyone the first time. A large share of violations on any public site come from browser extensions injecting scripts into your pages, from ISPs and antivirus products rewriting content, and from in-app browsers adding their own instrumentation. Common tells:

You cannot stop these — the extension runs in the user's browser, not yours — and you should not add them to your policy. Filter them out and move on. This is the main reason a hosted collector earns its keep: separating signal from extension noise at volume is tedious, and it is most of the work.

What you are looking for

Real findings look different. They appear consistently, on specific pages, across many users, pointing at origins you half-recognise: the tag manager, the font host, the A/B testing tool, the payment provider. Each one is a decision:

  1. Do I want this? If you cannot explain what it is, that is a finding in itself — you have just discovered a third party nobody documented.
  2. Does it need to be in the policy, or should it go away? A surprising number of these are dead tags nobody removed.
  3. If it stays, what is the narrowest way to allow it? Step 6 is about making that answer "a nonce" rather than "a growing list of hosts".

The reporting endpoint is a control, not a leak

You will occasionally read that CSP reporting is a data-exfiltration channel. The mechanism is real — a report body names the URL that was blocked, so a policy pointed at an attacker's endpoint would tell them things. But that requires the attacker to choose your report-uri, and if they can rewrite your response headers you have lost already. Pointed at an endpoint you control, reporting is how you find problems before someone else does.

You can do this now

Look at whatever your report-only policy from step 2 has collected. Find one violation that is not extension noise. That URL is a third party running on your site — do you know what it is?