# Script hash (/en/docs/web-security/reporting-api/reports/csp-hash)



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'`](/en/docs/web-security/policies/content-security-policy/values/report-sha-keyword) 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.

<Callout type="warn" title="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.
</Callout>

## When the browser sends it [#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 [#setup]

```http
Reporting-Endpoints: hashes-endpoint="https://<Endpoint-ID>.report.centralcsp.com"
```

```http
Content-Security-Policy-Report-Only: script-src 'self' 'report-sha256'; report-to hashes-endpoint
```

## Payload example [#payload-example]

```json
{
  "type": "csp-hash",
  "age": 12,
  "url": "https://example.com/",
  "user_agent": "Mozilla/5.0 ...",
  "body": {
    "documentURL": "https://example.com/",
    "subresourceURL": "https://example.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-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 [#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](/en/docs/platform/features/script-inventory), 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 [#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 [#gotchas]

<Callout type="info">
  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.
</Callout>

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 [#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 [#see-also]

* [report-sha keyword](/en/docs/web-security/policies/content-security-policy/values/report-sha-keyword)
* [Content Security Policy](/en/docs/web-security/policies/content-security-policy)
* [integrity-violation report](/en/docs/web-security/reporting-api/reports/integrity-violation)
* [Script inventory and SBOM](/en/docs/platform/features/script-inventory)
* [Script hash monitoring in CentralCSP](/en/docs/platform/monitoring/script-hash)
* [Reporting-Endpoints header](/en/docs/web-security/reporting-api/headers/reporting-endpoints)
* [The report delivery format](/en/docs/web-security/reporting-api/concepts/report-delivery-format)

## Sources [#sources]

* [Chrome, URL and eval hashes in CSP](https://developer.chrome.com/blog/script-src-hashes)
* [W3C, Content Security Policy editor draft](https://w3c.github.io/webappsec-csp/)
* [Chrome Platform Status](https://chromestatus.com/feature/6337535507431424)
