Healthcare websites are awkward from a CSP perspective.
You need strong browser-side protections because patient portals, appointment forms, billing pages, and telehealth flows are juicy targets for XSS and data exfiltration. But the same sites also tend to be loaded with analytics, consent tools, scheduling widgets, chat vendors, CDNs, and old CMS fragments that fight every strict policy you try to deploy.
And then HIPAA changes the stakes. A normal marketing site can shrug off some tracking sprawl and say “we’ll clean it up later.” A healthcare site that leaks PHI through JavaScript, third-party requests, or embedded tools is in a much worse spot.
So the real question is not whether to use CSP. You should. The question is which CSP style gives you the best security-to-operational-pain ratio for a healthcare environment.
What CSP does for HIPAA work
CSP is not a HIPAA checkbox. HIPAA does not say “set script-src and call it a day.” But CSP absolutely supports HIPAA goals:
- reducing risk of unauthorized disclosure
- limiting where browser-loaded code can execute
- blocking rogue form submissions and framing
- making third-party data flows visible
- giving you reporting signals when something strange happens
If your site handles anything that could become PHI — appointment requests, patient messages, authenticated sessions, intake forms, billing workflows — browser controls matter. A lot.
I treat CSP as one layer in a stack with:
- output encoding and template safety
- strong session controls
- CSRF protection
- SRI where possible
- third-party vendor review and BAAs
- consent and data minimization
- secure headers like
Referrer-Policy,Permissions-Policy, andX-Content-Type-Options
CSP won’t save a sloppy app, but it does reduce blast radius.
The uncomfortable truth about healthcare sites
Most healthcare websites are really two sites smashed together:
- a public marketing site with trackers, forms, tag managers, and cookie banners
- a semi-sensitive or fully sensitive app experience
That split matters because the right CSP for a brochure site is not the right CSP for a patient portal.
If you use one loose policy everywhere, the risky parts inherit all the junk needed by marketing pages. That’s a mistake I see constantly.
My opinion: split CSP by application area. Public pages can tolerate a broader policy if you absolutely must. Authenticated and PHI-adjacent pages should be much tighter, ideally with different infrastructure and different headers.
A real-world header and what it tells us
Here’s the CSP header you provided from headertest.com:
content-security-policy:
default-src 'self' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
script-src 'self' 'nonce-ZDIzYzE0YzYtOWE5Zi00ZmJlLTlkZDctODhkNTY3YmYxZmMw' 'strict-dynamic'
https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
style-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://*.cookiebot.com https://consent.cookiebot.com;
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.headertest.com https://tallycdn.com https://or.headertest.com
wss://or.headertest.com https://*.google-analytics.com https://*.googletagmanager.com https://*.cookiebot.com;
frame-src 'self' https://consentcdn.cookiebot.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
object-src 'none'
This is pretty normal for a modern site. Also pretty normal: it would make me nervous on pages handling healthcare data.
What I like
object-src 'none'is correct.base-uri 'self'is good hardening.form-action 'self'is a strong control for form exfiltration.frame-ancestors 'none'blocks clickjacking well if framing is not needed.- nonce-based
script-srcwith'strict-dynamic'is a strong modern pattern.
What I don’t like for healthcare-sensitive pages
- Google Tag Manager and Google Analytics are present. That’s a governance problem as much as a CSP problem.
style-src 'unsafe-inline'weakens protection.img-src https:is broad. Any HTTPS image endpoint is allowed.default-srcincludes third-party domains. I prefer usingdefault-src 'self'and being explicit elsewhere.connect-srcallows several analytics and service endpoints. On PHI pages, every outbound connection deserves scrutiny.
For a public healthcare marketing page, this might be acceptable with strong internal policy and no PHI collection. For authenticated patient workflows, I’d call it too permissive.
Three CSP approaches for healthcare sites
1. Broad compatibility CSP
This is the “make the site work without upsetting marketing” option.
Example:
Content-Security-Policy:
default-src 'self' https://www.googletagmanager.com https://*.cookiebot.com;
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://*.google-analytics.com;
frame-ancestors 'none';
object-src 'none';
Pros
- Easy to deploy on legacy CMS stacks
- Fewer breakages
- Useful as a first migration step
- Better than having no CSP
Cons
- Weak XSS protection
- Often allows exactly the third-party sprawl that causes HIPAA headaches
'unsafe-inline'and'unsafe-eval'are bad habits that tend to stick around forever- Hard to defend on sensitive pages
My take: only use this as a transitional policy, and never pretend it’s “HIPAA-safe” by itself.
2. Nonce-based strict CSP
This is the best fit for modern healthcare apps.
Example:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{RANDOM_NONCE}' 'strict-dynamic';
style-src 'self' 'nonce-{RANDOM_NONCE}';
img-src 'self' data:;
font-src 'self';
connect-src 'self' https://api.examplehealth.org;
form-action 'self';
frame-ancestors 'none';
base-uri 'self';
object-src 'none';
report-to default-endpoint;
And in HTML:
<script nonce="{{ .CSPNonce }}">
window.appConfig = { csrfToken: "{{ .CSRFToken }}" };
</script>
<script nonce="{{ .CSPNonce }}" src="/assets/app.js"></script>
Pros
- Strong defense against injected scripts
- Works well with modern frameworks and server rendering
- Great for patient portals, billing, and messaging pages
- Makes unauthorized third-party scripts much harder to introduce
Cons
- Requires engineering discipline
- Inline scripts and styles need refactoring or nonce support
- Tag managers become painful, which honestly may be a feature
- Caching HTML gets trickier because nonce values must be per response
My take: this is the default target for anything that touches patient data.
3. Segmented CSP by risk level
This is what I recommend most often because it matches how healthcare sites actually work.
Public marketing pages
Allow only what you truly need. Maybe consent tooling, maybe a minimal analytics setup, maybe embedded maps or scheduling. Still keep it reasonably tight.
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{RANDOM_NONCE}' 'strict-dynamic' https://consent.example;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://images.examplecdn.com;
connect-src 'self' https://consent.example;
frame-src https://scheduler.example;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
object-src 'none';
Patient and PHI pages
Remove analytics, tag managers, ad tech, and “helpful” third-party widgets.
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{RANDOM_NONCE}' 'strict-dynamic';
style-src 'self' 'nonce-{RANDOM_NONCE}';
img-src 'self' data:;
font-src 'self';
connect-src 'self' https://api.portal.examplehealth.org;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
object-src 'none';
Pros
- Best balance of security and business reality
- Easier to justify in audits and internal reviews
- Reduces accidental PHI exposure to third parties
- Lets public pages stay functional without poisoning secure areas
Cons
- More operational complexity
- Requires clean route separation
- Teams need to understand which vendors are allowed where
My take: if you run both a public site and a patient-facing app, this is the sane path.
HIPAA-specific pain points CSP can help expose
Analytics on appointment and portal pages
If your connect-src, img-src, or script-src includes analytics vendors on pages where users submit symptoms, insurance data, account details, or messages, you have a governance problem. CSP won’t fix that alone, but it makes the dependency visible.
Third-party chat and scheduling widgets
A lot of healthcare organizations bolt on chat bubbles and booking tools. Some are fine with the right agreements and configuration. Some are data vacuums. If a widget needs half the internet in script-src, connect-src, img-src, and frame-src, I get suspicious fast.
Inline scripts in old CMS templates
Nonce-based CSP usually reveals hidden messes: inline handlers, legacy snippets, random A/B testing code. Annoying, yes. Useful, also yes.
Practical recommendations
- Split policies by sensitivity. Don’t serve GTM-friendly CSP on patient pages.
- Use nonce-based
script-srcfor apps. Prefer'strict-dynamic'over giant allowlists. - Keep
default-src 'self'. Be explicit with other directives. - Avoid broad sources like
https:inimg-srcunless you really mean it. - Use
form-action 'self'andframe-ancestors 'none'by default. - Remove analytics from PHI-adjacent flows unless there’s a very strong reason and proper governance.
- Start with Report-Only before enforcement, but don’t leave it there for six months.
- Document every third-party domain and why it exists. If nobody can explain it, cut it.
For ready-to-use policy patterns, csp-examples.com is handy for quick starting points. For exact browser behavior, the official reference is the MDN CSP documentation.
My recommendation
If I were setting policy for a healthcare site today:
- Public brochure pages: moderately strict CSP, minimal vendors, aggressive cleanup
- Login, portal, billing, forms, telehealth, messaging: strict nonce-based CSP with no marketing tags
- Admin interfaces: even tighter, often with separate hostnames and no third-party scripts at all
That headertest.com policy is a decent example of a modern general-purpose CSP. For healthcare, I’d treat it as a starting point for low-risk pages, not the finish line.
If a page can expose PHI, I want the browser loading as little third-party code as possible. Honestly, that one principle will get you farther than endless debates about which directive is more elegant.