Deliberate inline-script file
script-src 'self' excludes inline script. The report-only disposition still lets this test statement run.
The CSP Report-Only header tests a policy without blocking content. Use it to collect violation reports, refine required sources, and reduce breakage before enforcement.
Replace the sample origins with your application's sources and the report URLs with a collector you operate. Send both lines as HTTP response headers on the pages you want to test.
Need a candidate policy? Use the CSP scanner and header generator, then adapt its output for report-only testing. This example pairs Reporting-Endpoints with report-to and includes deprecated report-uri for legacy reporting. Script Sentinel does not provide a hosted public collector.
Check the delivered headers and prove the reporting path works before interpreting a quiet result. An existing enforced CSP can still block content; adding report-only does not disable it.
Use this sequence to turn a candidate header and its CSP violation reports into reviewable evidence. A quiet collector is not a pass unless reporting itself and the required application states were tested.
A CSP report describes an action that violated a page's Content Security Policy. It can identify the page, the applicable directive, the blocked source, and whether the policy was reporting or enforcing. A report is a lead to investigate, not proof of an attack or a reason to allow the reported source.
type: "csp-violation" and a body; legacy reports use a csp-report object. Field names differ between these formats.documentURL / document-uri and originalPolicy / original-policy with the response you are testing. Delayed reports may describe an older policy.report identifies report-only evaluation; enforce identifies an enforcing policy. Do not infer which policy fired only from whether the page appeared to work.effectiveDirective / effective-directive and blockedURL / blocked-uri. For example, script-src-elem with inline points to an inline script element; it is not a domain to add to an allowlist.For the inline-script case, the controlled walkthrough demonstrates moving the statement into a same-origin script file. Other cases may need a nonce or exact hash. Avoid adding 'unsafe-inline' simply to silence reports.
Treat received fields as untrusted input, and do not interpret missing reports as proof of safety. This guide explains report interpretation and collection; Script Sentinel does not offer a hosted public CSP report collector.
This report-only CSP header tests a policy without blocking scripts, images, frames, or API connections that violate it.
Scope: This is a controlled teaching lab, not a customer result. Run it only on a staging origin you control. The same-origin /csp-report path represents a bounded collector you operate; Script Sentinel does not host that endpoint.
Observed lab result: In a clean headless Chrome 152.0.7977.64 loopback run, the starting statement executed and produced both a matching violation event and collector POST. After the same statement moved to /static/lab.js under the unchanged header, it executed without that matching inline event or POST during a 500 ms post-load observation within a 2.5-second virtual-time run. This validates the minimal fixture, not other browsers or application flows.
/lab.html, save the starting HTML as that file, and make POST /csp-report return a small success response after bounded processing./lab.html in a clean browser profile. Lab script ran confirms that the statement executed; that page result alone does not prove the browser received the header or emitted a report.securitypolicyviolation event, or collector request with the field values documented below. Execution plus that matching signal shows the report-only policy observed the statement without blocking it./lab.html with the corrected HTML, save the moved statement as /static/lab.js, and repeat the test. Then temporarily restore the starting /lab.html; the matching inline signal must return before you count the quiet corrected pass as meaningful.Keep this policy unchanged between the starting and corrected files so the retest isolates the code change. The legacy report-uri keeps this small lab easy to inspect; use the compatibility guidance below for production reporting.
script-src 'self' excludes inline script. The report-only disposition still lets this test statement run.
Move the statement into /static/lab.js. The existing 'self' source permits the external script without adding 'unsafe-inline'.
For this starting file, use only the matching observation: disposition = report, effectiveDirective / effective-directive = script-src-elem, blockedURL / blockedURI / blocked-uri = inline, and originalPolicy / original-policy matching the exact policy value in the lab response header.
Page result
Lab script ran is the execution control only. Pair it with the matching violation signal before concluding that report-only observed the statement. A separate enforced policy can still block content.
disposition: report
The matching signal must say report; this ties it to monitoring rather than enforcement. Never infer disposition from whether the feature appeared to work.
effectiveDirective / effective-directive
The value should be script-src-elem. The inline element is governed by script-src through CSP fallback because this candidate has no separate script-src-elem.
blockedURL / blockedURI / blocked-uri
The value should be inline. It identifies the kind of resource the policy would reject; it is evidence to locate code, not a reason to allow every inline script.
originalPolicy / original-policy
It should match default-src 'self'; script-src 'self'; report-uri /csp-report;. Delayed reports from an older candidate must not justify a current change.
Classification to correction to retest
After verifying the code is owned and required, externalize the identical statement to same-origin /static/lab.js. The corrected page should still say Lab script ran without that matching inline signal; temporarily restore the starting HTML and confirm the signal returns.
This closes one reproduced finding only. If externalizing is impractical, evaluate a per-response nonce or an exact hash. Do not add 'unsafe-inline' reflexively, and do not treat this lab as proof that untested routes, states, or browsers are ready for enforcement.
application/reports+json)The report-to directive uses the Reporting API. The browser sends a JSON array and can batch multiple reports in one request. CSP entries use type: "csp-violation" and camelCase body fields.
report-uri payload (application/csp-report)The deprecated report-uri directive sends one JSON object with a top-level csp-report envelope and kebab-case field names. Collectors may still need this format for older browser behavior.
blockedURL / blocked-uri
The source the browser would have blocked under the tested policy.
effectiveDirective / effective-directive
The directive that controlled the resource after CSP fallback behavior.
documentURL / document-uri
The document where the violation was observed.
sourceFile / source-file
The page, script, or stylesheet that triggered the blocked load when the browser can identify it.
lineNumber / line-number
The reported line for the attempted load, useful when tracking inline scripts or injected code.
disposition
report means report-only. enforce means the browser blocked the resource.
report-to and report-uri?report-to is the modern mechanism and is intended to replace report-uri, but older browser versions may only use the legacy directive. When both appear, browsers that use report-to ignore report-uri; legacy implementations can still post to the fallback URL.
Test the browser versions you support. Reporting can be delayed, batched, disabled, or dropped, so the absence of reports is not proof that a policy is ready to enforce.
application/reports+json contains an array that may hold several report types; process each supported csp-violation entry independently.application/csp-report contains one legacy csp-report envelope.Content-Type, reject malformed or oversized bodies, and return a small success response after bounded processing.This is design guidance for a collector you operate. Script Sentinel does not currently provide a hosted public CSP violation collector.
sample, script-sample, URLs, referrers, user-agent text, and policy text as untrusted content.Report URLs, referrers, source locations, policy text, and code samples can expose account paths, query tokens, personal data, or application details. Collect only what the review workflow needs.
For protocol details, consult the W3C Content Security Policy reporting specification and Reporting API specification.
Debug the delivery path, active headers, browser behavior, collector response, and exercised application state separately. A quiet collector is not proof that an enforced policy is ready.
No request reaches the collector
Confirm the final document response contains the report-only policy, the report-to group exactly matches Reporting-Endpoints, the endpoint is HTTPS, and a deliberate violation actually occurs.
The browser still blocks content
Look for a second enforced Content-Security-Policy header or meta policy. Report-only does not disable or override an enforced policy already present.
sample is empty
Code samples are not guaranteed and may be omitted or truncated. Diagnose with the effective directive, blocked URL, document URL, source file, disposition, and a reproduction path.
One violation floods storage
Repeated components, retries, and multi-page flows can emit the same finding many times. Sanitize first, then aggregate a bounded fingerprint with counts and first/last-seen times.
Unknown browser-extension origins
Extensions can inject scripts or styles that are not part of the application. Separate extension-shaped noise from origins reproduced in a clean browser profile before changing policy.
Reports appear only after consent or login
Analytics, payments, chat, and authenticated application code may load only after a state transition. Test representative consent choices, sessions, routes, and user actions.
Reporting API delivery can be delayed, batched, rate-limited, disabled, or dropped. During the compatibility period, accept both report media types and use deprecated report-uri alongside report-to when your browser support requirements justify it.
No. Report-only CSP evaluates the policy and reports violations, but the browser continues loading the page.
Move to enforcement when violations are reviewed, required sources are accounted for, and the policy no longer blocks expected user flows.
They usually test the same resource and navigation restrictions, but report-only is not a complete simulation of enforcement. The sandbox and upgrade-insecure-requests directives have no effect in report-only, and a report-only policy must be delivered in an HTTP response header rather than a meta element. Review the final enforced header separately and introduce it with a bounded rollback plan.
report-to uses the modern Reporting API and application/reports+json, while deprecated report-uri uses application/csp-report and supports older reporting behavior. During a compatibility transition, send Reporting-Endpoints, include both directives, and make the collector accept both payload formats.
No. Treat every field as attacker-controlled. Enforce request and field limits, sanitize before storage, escape before display, rate-limit and deduplicate submissions, redact sensitive URL and sample data, and apply a documented retention period.
Run a Chrome-based CSP scanner first so your report-only header starts from observed resource behavior instead of a blank policy.