37 Audits
πŸ›‘οΈ

Content Security Policy Auditor

Security Auditor

Validates Content-Security-Policy header configuration

Security
20 credits
Per check
~30 seconds
Average runtime
Active
Status

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, 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, W3C Working Draft as of 2026-10-15. It does not change the overall status.

What this auditor validates

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.

CheckCodeStatusWhen it firesRecommendationWhy it matters
37A-CSPAuditor-100INFORMATIONAlways. Records the specification version this auditor implements.β€” (recommendation is null; nothing for the site to change)β€”
37A-CSPAuditor-400FAILThe 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-300WARNINGThe 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-301WARNINGA 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-302WARNINGEvery 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-303WARNINGEvery 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-304WARNINGEvery 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-200SUCCESSAll rules passed. Message names the script directive and its sources.β€”β€”
37A-CSPAuditor-500ERRORThe 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-590ERRORThe 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.

Output Documentation

StatusDescriptionTest logic
SUCCESSScripts are restricted by an enforced policyAn enforced policy governs scripts and no policy weakness applies (200).
WARNINGA policy exists but does not stop injected scriptsReport-only policy only (300); no script directive (301); 'unsafe-inline' (302); 'unsafe-eval' (303); wildcard script source (304).
FAILNo Content Security PolicyNo enforced header, meta tag or report-only policy (400).
ERRORThe auditor could not read the pageFetch failure or non-2xx answer (500); site blocked 37AuditsBot (590).
INFORMATIONSpecification pinAlways 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, a developer documentation platform.

Source: docs.37audits.com

Ready to start auditing?

Add this auditor to your monitoring setup and start identifying issues on your websites today.

Β© 2026 37 Audits. All rights reserved. Audit your websites with confidence.

Supported by

Made with ❀️ in Floripa