Troubleshooting
Solutions for common CSP configuration issues.
Reports Not Appearing
Section titled “Reports Not Appearing”Check for an Ad Blocker First
Section titled “Check for an Ad Blocker First”This is the most common cause, and the only one with no local symptom. Content blockers — uBlock Origin, Adblock Plus, Brave Shields, Privacy Badger and others — block the browser’s POST to any reporting endpoint. There is no console error, no CSP violation, and nothing in DevTools that reads as a failure to a non-expert. Reports simply never arrive, and a correctly configured site looks identical to one that has had no violations.
To confirm it:
- Open DevTools and switch to the Network tab.
- Reload the page and trigger a violation.
- Look for a request to
ingest.headerhawk.com. If it is missing, or shows as cancelled or blocked, an extension is the cause. - Disable the extension for your origin and reload. Reports should appear within a minute.
Check the Reporting Domain Matches
Section titled “Check the Reporting Domain Matches”Reports are matched against the domain registered for the site, exactly. A
site registered as example.com accepts reports from example.com and
discards reports from www.example.com, app.example.com, and every other
subdomain.
This matters most when one CSP header is deployed across several hosts, which is the normal case. The endpoint returns the same success status whether a report was stored or discarded — deliberately, so that the response cannot be used to discover which domains a tenant monitors — so nothing in the browser shows a problem.
To check, go to Settings → Sites, open the site’s row menu and choose View Setup. If reports have been discarded for a domain mismatch, the panel lists how many and which hosts they came from. If a listed host is one of yours, add it as its own site to start collecting its reports.
Check Your Header
Section titled “Check Your Header”Verify the CSP header is being sent:
curl -I https://your-site.com | grep -i content-security-policyYou should see either Content-Security-Policy or Content-Security-Policy-Report-Only.
Verify the Report URI
Section titled “Verify the Report URI”Ensure your report-uri directive is correct:
report-uri https://ingest.headerhawk.com/csp/YOUR_INGEST_CODECommon mistakes:
- Missing
https:// - Wrong ingest code
- Typo in the domain name
Test Manually
Section titled “Test Manually”Send a test report. Use your own registered domain as the document-uri —
a report whose document-uri does not match the site’s domain is discarded, and
the response looks identical either way:
curl -i -X POST \ https://ingest.headerhawk.com/csp/YOUR_INGEST_CODE \ -H "Content-Type: application/csp-report" \ -d '{"csp-report":{"document-uri":"https://your-site.com/","violated-directive":"script-src","original-policy":"default-src self"}}'Other statuses do tell you something:
| Status | Meaning | What to do |
|---|---|---|
404 |
Nothing is accepting reports for that ingest code: either no site has it, or the site it belongs to is deactivated | Check the code against the site’s setup panel, then check the site is active |
400 |
The path is not /csp/{8-character code}, or the report body failed validation |
Check the URL shape, and that the body has document-uri, violated-directive and original-policy |
429 |
Rate limited, or the tenant is past its monthly hard quota | Back off, or check usage in the dashboard |
404 covers both the unknown-code and the deactivated-site case, and does not
say which. That is deliberate, for the same reason a domain-mismatch drop still
returns 204: the ingest code sits in the report-uri of every page that uses
it, so it is public by construction, and a status that distinguished “real
code” from “no such code” would let anyone work through the 8-character
keyspace and confirm which codes belong to real customers. Both of your own
cases are visible from the dashboard, where the ambiguity costs you nothing.
Browser Console
Section titled “Browser Console”Check the browser console for CSP messages. Violations appear as warnings even in report-only mode.
Script Hash Reports Not Appearing
Section titled “Script Hash Reports Not Appearing”Script integrity reporting ('report-sha256') has its own set of silences,
separate from violation reporting. This section is the diagnostic short list;
Script Integrity Monitoring explains the
mechanism in full — what the data covers, how sampling works, and how to read
the Origins, Scripts and Pages views.
It needs the Reporting API, not report-uri
Section titled “It needs the Reporting API, not report-uri”A hash report is a Reporting API report type. report-uri predates report
types and carries CSP violation reports only, so it has no way to deliver a
hash report. A policy combining 'report-sha256' with report-uri looks
correct and reports nothing.
Use the Reporting-Endpoints header with report-to:
Reporting-Endpoints: csp-endpoint="https://ingest.headerhawk.com/csp/YOUR_INGEST_CODE"Content-Security-Policy-Report-Only: script-src 'self' 'report-sha256'; report-to csp-endpointNote the quotes. 'report-sha256' is a keyword source expression and must be
quoted and placed inside script-src; bare report-sha256 is parsed as a
hostname and does nothing.
A cached script produces no hash
Section titled “A cached script produces no hash”The browser generates a hash when it fetches and executes a script. On a normal reload an external script is usually served from cache, no fetch happens, and no hash is generated — however correct your policy is. A hard refresh (shift+reload) forces the fetch, which removes caching as an explanation; it is not a guarantee that a report will follow, since support is still narrow (see below).
The same effect applies to real traffic: a site with well-cached assets reports far fewer hashes than it has scripts, and returning visitors contribute almost none. Combined with the sample rate, treat the Scripts page as a sample of your scripts rather than a complete inventory.
Browser support is narrow
Section titled “Browser support is narrow”Chromium 133+ implements report-sha256; WebKit support is in progress;
Firefox does not support it. Some Chromium builds accept the keyword and emit
no hash reports at all. An empty Scripts page is not by itself evidence of a
misconfiguration — see
Browser support is narrow
for what has actually been observed.
Site Breaking After Adding CSP
Section titled “Site Breaking After Adding CSP”Start with Report-Only
Section titled “Start with Report-Only”Always use Content-Security-Policy-Report-Only first:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri https://ingest.headerhawk.com/csp/YOUR_INGEST_CODEThis reports violations without blocking anything.
Common Resources That Break
Section titled “Common Resources That Break”| Issue | Solution |
|---|---|
| Inline scripts blocked | Add 'unsafe-inline' or use nonces |
| CDN scripts blocked | Add the CDN domain to script-src |
| Google Fonts blocked | Add fonts.googleapis.com and fonts.gstatic.com |
| Images not loading | Add domains to img-src or use https: |
| API calls failing | Add API domain to connect-src |
Finding Blocked Resources
Section titled “Finding Blocked Resources”- Open browser DevTools
- Go to the Console tab
- Look for “Refused to…” messages
- Note the blocked URL and violated directive
Too Many Reports
Section titled “Too Many Reports”Reduce Noise
Section titled “Reduce Noise”Some violations are expected or from browser extensions. Filter in HeaderHawk dashboard by:
- Document host (your domains only)
- Blocked host (exclude known extension domains)
- Directive (focus on critical directives)
Common False Positives
Section titled “Common False Positives”| Source | Cause | Action |
|---|---|---|
chrome-extension:// |
Browser extensions | Filter out in dashboard |
moz-extension:// |
Firefox extensions | Filter out in dashboard |
about:blank |
Injected iframes | Usually safe to ignore |
localhost |
Dev tools or extensions | Filter out in dashboard |
Switching to Enforce Mode
Section titled “Switching to Enforce Mode”Pre-Switch Checklist
Section titled “Pre-Switch Checklist”- Run in report-only mode for at least a week
- Review all violation types in the dashboard
- Add legitimate resources to your policy
- Test critical user flows
- Have a rollback plan
Making the Switch
Section titled “Making the Switch”Change the header from:
Content-Security-Policy-Report-Only: ...To:
Content-Security-Policy: ...Keep the report-uri to continue receiving reports about enforced blocks.
Rollback Plan
Section titled “Rollback Plan”If things break:
- Immediately revert to
Content-Security-Policy-Report-Only - Check new violations in the dashboard
- Update policy to allow legitimate resources
- Try enforcing again
Specific Issues
Section titled “Specific Issues”Inline Scripts
Section titled “Inline Scripts”Problem: Refused to execute inline script
Solutions:
- Move to external file (recommended)
- Use nonce:
Content-Security-Policy: script-src 'nonce-abc123'<script nonce="abc123">...</script>
- Use hash:
Content-Security-Policy: script-src 'sha256-...'
- Allow unsafe-inline (not recommended):
Content-Security-Policy: script-src 'unsafe-inline'
Inline Styles
Section titled “Inline Styles”Problem: Refused to apply inline style
Solutions:
- Move styles to external CSS file
- Use
'unsafe-inline'for styles (lower risk than scripts):Content-Security-Policy: style-src 'self' 'unsafe-inline'
eval() and Function()
Section titled “eval() and Function()”Problem: Refused to evaluate a string as JavaScript
Cause: Your code or a library uses eval(), new Function(), or similar.
Solutions:
- Replace with safer alternatives
- If unavoidable, add
'unsafe-eval'(security risk):Content-Security-Policy: script-src 'unsafe-eval'
WebSocket Connections
Section titled “WebSocket Connections”Problem: WebSocket connection refused
Solution: Add to connect-src:
Content-Security-Policy: connect-src 'self' wss://your-websocket-server.comFrames and Embeds
Section titled “Frames and Embeds”Problem: Cannot load content in iframe
Solution: Add source to frame-src:
Content-Security-Policy: frame-src 'self' https://youtube.com https://player.vimeo.comGetting Help
Section titled “Getting Help”If you’re stuck:
- Check the browser console for specific error messages
- Review violations in the HeaderHawk dashboard
- Search for the specific directive and error message
- Test with a minimal policy and add directives incrementally