Script hash
The csp-hash report sends a hash of every script the page loads, the basis for a browser-side script inventory.
Last update:
A csp-hash report carries the hash of a script (or other subresource) the page
loaded. Unlike a violation report, it is not about something being blocked: you opt
in with a 'report-sha256' source expression and the browser reports a hash for
every matching resource. That stream is how you build an inventory of the scripts
actually running in the browser, mapped to library, version, and known CVEs.
Chromium-only
Script hash reporting ships enabled by default in Chromium, so it is on without an origin trial, but it is Chromium-only: Firefox and Safari do not send it. The field casing also differs from the CSP draft (see Gotchas), so treat the payload as Chromium-specific. See Browser support below.
When the browser sends it
When a script-like directive carries 'report-sha256' (or 'report-sha384' /
'report-sha512'), the browser emits one csp-hash report for each matching
resource it loads, and also prints the hash to the DevTools console. It reports
rather than blocks, so it does not affect what runs. Hash reports are not exposed to
ReportingObserver; they only go to the endpoint.
Setup
Reporting-Endpoints: hashes-endpoint="https://<Endpoint-ID>.report.centralcsp.com"Content-Security-Policy-Report-Only: script-src 'self' 'report-sha256'; report-to hashes-endpointPayload example
{
"type": "csp-hash",
"age": 12,
"url": "https://api-next.centralcsp.com/",
"user_agent": "Mozilla/5.0 ...",
"body": {
"documentURL": "https://api-next.centralcsp.com/",
"subresourceURL": "https://api-next.centralcsp.com/main.js",
"hash": "sha256-85738f8f9a7f1b04b5329c590ebcb9e425925b6c0d...",
"type": "subresource",
"destination": "script"
}
}Every csp-hash report body carries these fields inside the shared report envelope.
Field reference
| Field | Meaning |
|---|---|
documentURL | The page the script loaded on. |
subresourceURL | The URL of the loaded script or resource. |
hash | The hash as <alg>-<base64>, for example sha256-.... |
type | The hash category (for example subresource). |
destination | The request destination, for example script. |
How to receive it
Declare an endpoint and add 'report-sha256' to script-src; keep the policy in
Report-Only so it never blocks. This is the exact mechanism behind the CentralCSP
script inventory and SBOM, which maps
each reported hash to a technology, version, and known CVEs, with no snippet or
browser extension required.
What it tells you about security
A script hash you did not deploy is a supply-chain signal: a tampered CDN asset, an injected formjacking or Magecart script, or an unexpected third party. Continuous hash reporting plus alerting on new or changed hashes is how you catch that change the moment it reaches a real browser, rather than in a post-incident review.
Gotchas
Field casing is unsettled: Chromium emits camelCase (documentURL, subresourceURL) while the CSP editor draft example uses snake_case (document_url, subresource_url). Confirm against a live capture.
An earlier design used a 'report-hashes' keyword; the shipped keyword is
'report-sha256' (and the sha384/sha512 variants). The keyword and report shape are
still evolving in the CSP draft, so expect them to change.
Browser support
Chromium-based browsers only, where it ships enabled by default. Firefox and Safari do not support it. The field shape follows Chromium rather than the CSP draft, so treat any captured payload as Chromium-specific.
See also
- report-sha keyword
- Content Security Policy
- integrity-violation report
- Script inventory and SBOM
- Script hash monitoring in CentralCSP
- Reporting-Endpoints header
- The report delivery format