> ## Documentation Index
> Fetch the complete documentation index at: https://docs.37audits.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CSP Auditor

> Checks that a Content Security Policy limits which scripts can run on the page

<Info>
  **Security Auditor** — checks that the audited page enforces a `Content-Security-Policy` that restricts scripts, without `'unsafe-inline'`, `'unsafe-eval'` or wildcard script sources.
</Info>

<CardGroup cols={2}>
  <Card title="Protection" icon="shield-halved">
    Limits the damage of cross-site scripting (XSS): injected scripts are blocked by the browser.
  </Card>

  <Card title="Standards" icon="book">
    Follows W3C Content Security Policy Level 3, parsed and evaluated with the salvation2 library.
  </Card>
</CardGroup>

A Content Security Policy tells the browser which scripts, styles and other resources a page may load. When an attacker manages to inject a script into the page (cross-site scripting), a strict policy stops the browser from running it. This auditor reads the policies the audited URL sends and reports the weaknesses that let injected scripts through.

## How it works

1. **Fetch** — sends a `GET` request to the audited URL as 37AuditsBot. A blocked request ends the audit with `590`; any other failure (timeout, DNS, TLS, non-2xx answer) ends it with `500`.
2. **Collect policies** — every `Content-Security-Policy` header line (including several policies joined by commas) and every `<meta http-equiv="Content-Security-Policy">` tag in the page `<head>` are enforced policies. `Content-Security-Policy-Report-Only` enforces nothing and only matters when no policy is enforced.
3. **Evaluate** — each policy is parsed with [salvation2](https://github.com/shapesecurity/salvation), which implements the CSP Level 3 algorithms. The script directive is `script-src-elem`, else `script-src`, else `default-src`. Nonces, hashes and `'strict-dynamic'` are honoured: browsers ignore `'unsafe-inline'` next to them, and host sources next to `'strict-dynamic'`.
4. **Several policies** — the browser enforces every policy, so a weakness is reported only when every enforced policy allows it. One strict policy blocks the script even if another policy is loose.
5. **Aggregate** — FAIL wins over WARNING; when every rule passes the audit is `SUCCESS` (`200`).
6. **Specification pin** — every run emits `37A-CSPAuditor-100` (`INFORMATION`), naming [Content Security Policy Level 3](https://www.w3.org/TR/CSP3/), W3C Working Draft as of 2026-10-15. It does not change the overall status.

## What it audits

Every row maps to one `checkRule*` method and one `CheckCode`, in the order the auditor runs them. CheckCode suffixes use status ranges: `100` information, `200` success, `300–399` warning, `400–499` fail, `500–599` error.

| CheckCode | Status | When it fires | Recommendation | Why it matters |
| - | - | - | - | - |
| <a id="37A-CSPAuditor-100" />`37A-CSPAuditor-100` | `INFORMATION` | Always. Records the specification version this auditor implements. | — (recommendation is `null`; nothing for the site to change) | — |
| <a id="37A-CSPAuditor-400" />`37A-CSPAuditor-400` | `FAIL` | The page sends no `Content-Security-Policy` header, no CSP meta tag and no report-only policy. | Add a Content-Security-Policy header to `{url}`, starting with "default-src 'self'; object-src 'none'; base-uri 'self'" and loosening it for the sources the page needs. | A Content Security Policy is the browser's last line of defence against injected scripts. Without one, a single XSS bug lets attackers steal sessions and data or deface the site. |
| <a id="37A-CSPAuditor-300" />`37A-CSPAuditor-300` | `WARNING` | The page sends only `Content-Security-Policy-Report-Only`, so nothing is enforced. | Once the reports are clean, send the same policy "`{reportOnly}`" as Content-Security-Policy on `{url}` so the browser enforces it. | Report-only mode is a rehearsal: it shows what the policy would block but stops no attack. |
| <a id="37A-CSPAuditor-301" />`37A-CSPAuditor-301` | `WARNING` | A policy is enforced, but none has `script-src-elem`, `script-src` or `default-src`. | Add "script-src 'self'" (or a default-src) to "`{policy}`" on `{url}`. | A policy that does not mention scripts leaves the page as open to cross-site scripting as having no policy. |
| <a id="37A-CSPAuditor-302" />`37A-CSPAuditor-302` | `WARNING` | Every enforced policy lets an injected inline script run: `'unsafe-inline'` without a nonce, hash or `'strict-dynamic'`. | Remove 'unsafe-inline' from "`{sources}`" on `{url}` and allow inline scripts with nonces or hashes. | Allowing inline scripts lets the most common XSS payloads run, which removes most of the protection the policy is there to give. |
| <a id="37A-CSPAuditor-303" />`37A-CSPAuditor-303` | `WARNING` | Every enforced policy allows `eval()` through `'unsafe-eval'`. | Remove 'unsafe-eval' from "`{sources}`" on `{url}` and replace eval() and new Function() in the page scripts. | eval turns injected text into running code, so an attacker who controls a string can run scripts despite the policy. |
| <a id="37A-CSPAuditor-304" />`37A-CSPAuditor-304` | `WARNING` | Every enforced policy lets a script load from an arbitrary host because the script sources include `*`, `http:`, `https:` or `data:`. | Replace `{wildcards}` in "`{sources}`" on `{url}` with the specific hosts the page loads scripts from. | A wildcard script source lets attackers load their own script from any server, so the policy blocks almost nothing. |
| <a id="37A-CSPAuditor-200" />`37A-CSPAuditor-200` | `SUCCESS` | All rules passed. Message names the script directive and its sources. | — | — |
| <a id="37A-CSPAuditor-500" />`37A-CSPAuditor-500` | `ERROR` | The page could not be fetched (timeout, DNS, TLS, or a non-2xx answer other than a block). | Make sure `{url}` answers with HTTP 2xx, then run the audit again. Last error: `{error}`. | — |
| <a id="37A-CSPAuditor-590" />`37A-CSPAuditor-590` | `ERROR` | The audited page answered HTTP 403, HTTP 429 or a Cloudflare challenge, so 37AuditsBot was blocked before it could read the page. | Allow 37AuditsBot in your firewall or bot protection: allowlist its user agent, or verify its Web Bot Auth signature. See [https://www.37audits.com/bot](https://www.37audits.com/bot). | While 37AuditsBot is blocked this audit cannot look at the site, so problems on it go unreported. |

## Output documentation

| Status | Description | Test logic |
| - | - | - |
| **SUCCESS** | Scripts are restricted by an enforced policy | An enforced policy governs scripts and no policy weakness applies (`200`). |
| **WARNING** | A policy exists but does not stop injected scripts | Report-only policy only (`300`); no script directive (`301`); `'unsafe-inline'` (`302`); `'unsafe-eval'` (`303`); wildcard script source (`304`). |
| **FAIL** | No Content Security Policy | No enforced header, meta tag or report-only policy (`400`). |
| **ERROR** | The auditor could not read the page | Fetch failure or non-2xx answer (`500`); site blocked 37AuditsBot (`590`). |
| **INFORMATION** | Specification pin | Always emitted (`100`); does not change overall status. |

## Risks and considerations

### Why a Content Security Policy matters

* Cross-site scripting is one of the most common web vulnerabilities. An injected script runs with the visitor's session: it can read what they type, steal cookies and tokens, or change what the page shows.
* A strict policy is a second layer: even when a bug lets markup in, the browser refuses to run the injected script.

### Rolling out a policy

* Start with `Content-Security-Policy-Report-Only` to collect violation reports without breaking the site, then send the same policy as `Content-Security-Policy`. Keeping a report-only policy next to an enforced one, to test the next version, is fine and not reported.
* Prefer nonces or hashes with `'strict-dynamic'` over long host allowlists: they are easier to keep strict and survive CDN changes.

### What this auditor does not check

* Only the audited URL is fetched; other pages of the site may send a different policy.
* Only script restrictions are judged. `object-src`, `base-uri`, `frame-ancestors`, `style-src` and the other directives are recorded but not evaluated.
* Host allowlists are not checked for hosts that serve user-controlled JavaScript (JSONP endpoints, public CDNs), which can bypass a policy.
* Parse warnings from salvation2 (unknown directives, deprecated features) are kept in the check data, not reported as findings.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.