What breaks when a strict CSP blocks inline scripts and frame sources?
Inline scripts blocked: any <script>...</script> in HTML, javascript: URIs, inline event handlers (onclick='...'), eval/new Function — all fail silently. Strict CSP needs nonces or hashes for legitimate inline. frame-src blocked: any iframe (payment widgets, embedded videos, OAuth popups, third-party SSO) won't load. For embeds, host them on an allowed domain or coordinate with the merchant to add your domain to frame-src and script-src. Test with the merchant's CSP enabled in staging.
Content Security Policy (CSP) is a security header that whitelists allowed resources. When a merchant (or any host) sets a strict CSP, embedded widgets break unless they're explicitly allowed.
What inline-script restrictions break
Strict CSP without 'unsafe-inline' blocks:
1. Inline <script> blocks:
<script>doStuff();</script> ← blocked2. Inline event handlers in HTML:
<button onclick="doStuff()">Click</button> ← blocked3. javascript: URIs:
<a href="javascript:doStuff()">Click</a> ← blocked4. eval() and new Function():
eval('1 + 1') ← blocked without 'unsafe-eval'
new Function('return 1')();5. Inline styles (if style-src is similarly strict):
<div style="color: red">…</div> ← may be blocked6. Dynamic script injection (often used by analytics/tag managers):
const s = document.createElement('script');
s.innerHTML = '…';
document.head.appendChild(s); ← blocked if script content is inlineHow to legitimately do inline under strict CSP
Nonces: server generates a fresh random nonce per response and includes it in CSP + each allowed inline script tag:
Content-Security-Policy: script-src 'self' 'nonce-abc123'<script nonce="abc123">init();</script>Hashes: precompute SHA-256 of the inline script body, list in CSP:
Content-Security-Policy: script-src 'self' 'sha256-xyz...'Strict-dynamic: trust scripts loaded by already-trusted scripts:
Content-Security-Policy: script-src 'self' 'strict-dynamic' 'nonce-abc123'What frame-src restrictions break
frame-src (or child-src) controls which origins can be embedded as iframes.
Common breakage on strict frame-src:
- Payment widgets: Stripe Elements (iframes for card input), PayPal buttons, Apple Pay popups.
- Embedded videos: YouTube, Vimeo, Twitch.
- Embedded maps: Google Maps iframe embeds, OpenStreetMap.
- Social embeds: tweets, Instagram, Facebook posts.
- OAuth flows: third-party SSO popups (Google, GitHub, Microsoft).
- Chat widgets: Intercom, Drift, Zendesk.
- Analytics: some heatmap and session-replay tools (e.g., FullStory) iframe in.
- Captchas: reCAPTCHA, hCaptcha load in iframes.
What to do when integrating
If you're the embedded widget asking a merchant to embed you:
- Document your CSP requirements: tell merchants exactly which directives to add.
script-src https://js.yourservice.comframe-src https://yourservice.comconnect-src https://api.yourservice.comimg-src https://images.yourservice.com
- Minimize inline code so merchants don't need
'unsafe-inline'. - Use nonces or external scripts instead of inline.
- Provide nonced inline option if you must inline (publish-time hash, runtime nonce).
- Test on merchant's staging CSP before going live.
If you're the merchant setting CSP:
- Start in report-only mode to find what would break:
`` Content-Security-Policy-Report-Only: script-src 'self'; report-uri /csp-report ``
- Enumerate trusted origins from third parties you use.
- Use nonces for legitimate inline rather than
'unsafe-inline'. - Adopt strict-dynamic to simplify the policy.
- Iterate: tighten the policy as you remove inline scripts and reduce third-party sprawl.
Debugging
When a widget breaks under CSP:
- Browser console shows:
Refused to execute inline script because it violates the following Content Security Policy directive… - Network panel: blocked resources show
(blocked:csp)or similar. - Use
report-uri/report-toto collect violations from real users.
Other related CSP directives
default-src— fallback for unspecified directives.script-src— JS.style-src— CSS.img-src— images.font-src— fonts.connect-src— XHR/fetch/WebSocket.frame-src— iframes.frame-ancestors— who can embed YOU as iframe.form-action— where forms can submit.base-uri—<base>tag values.
Bonus: X-Frame-Options + frame-ancestors
If the merchant doesn't want to be embedded:
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGINPrevents anyone from embedding their site in an iframe. Defense against clickjacking.
Mental model
CSP is a contract between the page and the browser. Strict CSP closes most XSS attack surfaces, but it also breaks anything that uses inline JS, eval, or unallowed external origins. As a widget vendor, design for CSP-friendliness; as a merchant, adopt CSP gradually with report-only first.
Follow-up questions
- •How do nonces work in CSP?
- •What's strict-dynamic and why is it easier than nonces alone?
- •How do you collect CSP violation reports?
- •What's the difference between frame-src and frame-ancestors?
Common mistakes
- •Shipping inline scripts when targeting strict-CSP customers.
- •Using eval / new Function in libraries.
- •Not documenting CSP requirements for integrators.
- •Adding 'unsafe-inline' to make things work — defeats CSP's purpose.
- •Forgetting report-only mode during rollout.
- •Wildcard origins ('*') — defeats the whitelist.
Performance considerations
- •CSP has negligible perf overhead. The cost of CSP violations (broken widgets, failed payments) is far higher. Use report-only during rollout to catch issues without breaking production.
Edge cases
- •<base> tag injection — base-uri directive matters.
- •Service worker scripts have their own CSP rules.
- •WASM execution may need wasm-unsafe-eval.
- •Third-party tags that inject more scripts dynamically — strict-dynamic helps.
- •Stripe Elements specifically requires script-src 'self' js.stripe.com + frame-src js.stripe.com + connect-src api.stripe.com.
Real-world examples
- •Stripe documents exact CSP directives merchants need to add.
- •YouTube embeds require frame-src youtube.com.
- •GitHub uses strict CSP with nonces.
- •Google Search uses very tight CSP across its product surface.