Skip to content

Security

Content Security Policy and false confidence from a quick glance

Spotting the letters CSP in DevTools is not the same as confirming browser content sources are restricted by a CSP header on the URLs that matter.

· by Jonas Reed

Content Security Policy and false confidence from a quick glance

I have glanced at DevTools, seen a Content-Security-Policy value, and moved on. Later I noticed it was Report-Only, or only on the blog host, or so permissive that script-src might as well have been a comment. The glance found a string. It did not answer the actual question.

SlaySlop's CSP check "Checks whether browser content sources are restricted by a CSP header." Restriction is the verb. Presence of some CSP-shaped text is not automatically restriction.

Outcome I want from a CSP pass

I want fewer cases where visual security theater signs off and a response dump still shows an open content pipeline. On the URLs that handle money or accounts, an enforcing header should constrain script and object sources in a way you can explain in one paragraph.

What a quick glance gets wrong

A glance catches the header name in a panel. It misses host variance. It misses Report-Only versus enforcing. It misses that 'unsafe-inline' hollowed out the policy. It conflates CSP with HSTS: Strict Transport Security "Checks whether browsers are instructed to keep future requests on HTTPS." Different mechanism. Different failure mode.

I still start with curl when I want the raw signal:

bash
curl -sI "https://www.example.com/checkout" | rg -i 'HTTP/|content-security-policy|strict-transport|x-frame'

Then I read the policy text like a response shape, not like a badge.

Loading diagram.

Boundaries so I do not overclaim

Read-only public scan. Permission required. Not a pentest. Not an XSS proof. Cross-site scripting remains a separate check with its own templates. A quiet CSP row does not mean every inline event handler is gone from the HTML. It means the check's observation about CSP header restriction on scanned pages did not fire the way a missing or unrestricted policy would.

Meta tags and non-header delivery can confuse a glance. Keep the ticket language aligned with the published definition: CSP header.

Happy path that replaces the glance

  1. List launch URLs.
  2. Fetch response headers for each.
  3. Note enforcing vs Report-Only.
  4. Skim default-src, script-src, object-src, base-uri.
  5. Compare apex, www, and checkout hosts.
  6. Read SlaySlop CSP findings with page attachments instead of arguing from memory.
text
CSP glance replacement
url:
enforcing_header: yes|no
report_only: yes|no
script_src_summary:
object_src:
notes:

How the check observes a signal, in lab-notebook terms: the scanner requests public pages and inspects whether a CSP header restricts browser content sources. That is header observation, not a full browser policy simulator for every edge-case directive combination. Useful, bounded, actionable.

Pitfalls that recreate false calm

CDN UI showing a policy that is not attached to the hostname you tested. Preview headers leaking into screenshots used as "production proof." Marketing adding a new tag host after the glance. Equating "Security tab looks green in one browser extension" with SlaySlop's catalog definition.

When a tightened policy breaks a script, Console errors ("Captures runtime exceptions from a real browser session") may light up. That is feedback, not a reason to declare CSP a failed experiment and delete the header.

A slightly longer local ritual

When I have fifteen minutes, I dump headers for the demo path, save them next to the scan ID, and highlight any 'unsafe-inline' or missing object-src decisions. Dull ritual. Destroys false confidence faster than rereading a hardening blog post.

I also compare two moments in time: before a marketing tag change and after. CSP false confidence often regenerates the afternoon someone adds a pixel. The header still "exists." The restriction story may not.

What the response shape teaches

Headers are boring on purpose. They are also one of the few security signals you can quote verbatim in a ticket without a screenshot debate. When SlaySlop attaches a CSP finding to a page, I paste the observed header state under the URL. That habit stops the thread from drifting into vibes about "our platform is secure by default."

Sibling checks keep me honest. HSTS missing on the same host is a separate row. Frame protection missing is a separate row. Console errors after a tighten is feedback about allowlists, not proof that CSP was a bad idea.

When silence is still not confidence

No CSP finding on a brochure subdomain does not clear the checkout host. Coverage follows what was scanned. I re-read the URL list before I tell anyone the glance can stop.

Related next step

Replace the glance with a permissioned SlaySlop scan and a header dump on the same URLs. Soft link: Content Security Policy.