Validates Content-Security-Policy header configuration
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.
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.
Evaluate β each policy is parsed with salvation2, 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'.
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.
Aggregate β FAIL wins over WARNING; when every rule passes the audit is SUCCESS (200).
Specification pin β every run emits 37A-CSPAuditor-100 (INFORMATION), naming Content Security Policy Level 3, W3C Working Draft as of 2026-10-15. It does not change the overall status.
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 |
|---|---|---|---|---|
37A-CSPAuditor-100 | INFORMATION | Always. Records the specification version this auditor implements. | β (recommendation is null; nothing for the site to change) | β |
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. |
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. |
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. |
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. |
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. |
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. |
37A-CSPAuditor-200 | SUCCESS | All rules passed. Message names the script directive and its sources. | β | β |
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}. | β |
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. | While 37AuditsBot is blocked this audit cannot look at the site, so problems on it go unreported. |
| 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. |
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.
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.
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, a developer documentation platform.
Add this auditor to your monitoring setup and start identifying issues on your websites today.