How to Fix CSP unsafe-inline Without Breaking Your Site https://vulnify.app/blog/how-to-fix-csp-unsafe-inline Content-Security-Policy unsafe-inline weakens XSS defenses but breaking it overnight can halt analytics and styles. Learn a staged migration from unsafe-inline to nonces and hashes with the Vulnify CSP checker. Content-Security-Policy (CSP) is one of the most effective browser-side controls against cross-site scripting—but only when it is strict enough to matter. The directive combination script-src 'unsafe-inline' (and the style equivalent) tells browsers to allow inline scripts and event handlers, which largely negates the policy's purpose. Attackers who inject HTML can still run JavaScript in many scenarios. Teams keep unsafe-inline because legacy templates, tag managers, and CMS plugins depend on inline code. Removing it without a plan breaks checkout flows, analytics, and admin panels. This guide explains why unsafe-inline is flagged, how to inventory dependencies, and how to migrate in stages using Report-Only mode and the CSP checker before you enforce a stricter policy in production. Why unsafe-inline Is a Security Problem CSP works by whitelisting script sources. When unsafe-inline is present, any inline script block or attribute handler the page includes is permitted—including attacker-supplied markup reflected from a vulnerable form field or stored comment. Nonces and hashes restore the whitelist model: only scripts you explicitly authorize execute. Scanners and auditors flag unsafe-inline because it is a conscious relaxation of a control meant to limit XSS blast radius. It does not mean your site is actively compromised, but it does mean a successful injection has fewer browser-enforced guardrails. Pair CSP improvements with output encoding and framework defaults; headers are defense in depth, not a substitute for safe templating. Audit What Breaks Without unsafe-inline Before changing enforcement, capture the current policy and enumerate inline dependencies: Inline <script> blocks in templates and CMS widgets Event handlers such as onclick on buttons and links Third-party snippets injected by marketing tools Inline styles and style attributes when style-src 'unsafe-inline' is set JSON-LD or configuration blobs embedded in HTML Run the CSP checker against staging and production URLs. Compare delivered headers, note Report-Only policies if present, and save results for your change ticket. Our broader Permissions-Policy vs security headers guide explains how CSP fits alongside other browser policies. Report-Only: Test Before You Enforce Publish a parallel Content-Security-Policy-Report-Only header with stricter rules while keeping the enforcing policy unchanged. Browsers log violations without blocking resources, which lets you measure breakage during real traffic. Collect reports via report-uri or report-to endpoints, or use browser devtools during QA passes on critical user journeys. Typical staged target for script-src: remove unsafe-inline, add 'strict-dynamic' when using nonces on a bootstrap script, and maintain https: host allowlists only where necessary. Avoid copying example policies from blog posts without mapping each source to your stack—Shopify, WordPress, and React SPAs each need different allowlists. Nonces for Dynamic Pages A nonce is a random per-response token included in the CSP header and matching nonce attributes on allowed script tags. Your application server generates a fresh nonce per request and applies it to legitimate inline scripts. Frameworks and middleware exist for Node, PHP, Python, and .NET; the pattern is the same: one nonce per response, never reuse across users or cache shared HTML with static nonces. External scripts loaded by a nonce-approved bootstrap script can chain under 'strict-dynamic' in modern browsers, reducing endless host allowlists for CDNs. Test checkout, login, and password reset flows after enabling nonces—those pages often hide inline recovery snippets. Hashes for Static Inline Scripts When inline script content is identical on every response, SHA-256 hashes in CSP can authorize that exact block without nonces. Build pipelines can compute hashes at deploy time. Hashes fail silently when marketing changes one character in an inline snippet, so prefer nonces for frequently edited templates and hashes for stable JSON-LD or config blocks. Styles Are a Separate Conversation Removing style-src 'unsafe-inline' is harder on many sites because CMS themes and email-capture widgets inject inline styles. Some teams tighten script-src first and leave style-src relaxed temporarily, documented as accepted risk with a remediation ticket. Others use hashes for small inline style blocks or refactor to external stylesheets. The CSP checker shows both script and style directives so you prioritize script execution—the higher-impact XSS vector—first. Tag Managers and Third-Party Scripts Google Tag Manager and similar tools often encourage inline bootstrap snippets. Options include hosting the bootstrap as an external file on your domain, using nonce attributes on the container snippet, or moving tags to server-side tagging. Coordinate with marketing before enforcement day; otherwise campaign attribution disappears and teams revert the header under pressure. Validation Workflow Baseline current CSP with the CSP checker on production and staging. Inventory inline scripts and styles from templates and browser devtools Sources panel. Deploy Report-Only stricter policy; monitor violations for one business cycle. Implement nonces or hashes for required inline code; externalize what you can. Enforce stricter policy on staging; run automated and manual regression tests. Roll out enforcing header to production; re-run CSP checker to confirm delivery. Follow Vulnify Fix guides for copy-ready header examples where available, and align with vulnerability scanning best practices so header drift is caught on scheduled scans from the dashboard . Common Rollout Mistakes Teams sometimes enforce a strict CSP on the marketing site but forget admin subdomains still run unsafe-inline, creating a weak sibling host. Cached HTML with expired nonces causes intermittent blank pages—verify CDN cache keys include nonce or disable caching on HTML documents that embed them. Duplicate CSP headers from edge and origin may merge unpredictably; the checker helps confirm effective policy as browsers see it. When unsafe-inline Is Temporarily Acceptable Documented exceptions exist for legacy apps with no engineering bandwidth, but the exception should include an owner, review date, and compensating controls (strict output encoding, short session lifetimes, admin IP restrictions). Regulators and enterprise customers increasingly ask for CSP during security questionnaires; "we use unsafe-inline indefinitely" is a harder answer than "we are mid-migration with Report-Only metrics attached." Next Steps Run the CSP checker , list inline dependencies, test in Report-Only, then enforce nonces or hashes on staging before production. Combine with the security headers checker for HSTS and framing policies that complement CSP. Measuring Migration Success Define success metrics before you tighten enforcement: zero user-reported checkout failures for two weeks, CSP violation report volume below an agreed threshold, and CSP checker results showing no unsafe-inline on enforcing headers at both origin and CDN. Share dashboards with engineering and marketing so enforcement is a joint release, not a surprise security toggle. Document the final policy in your internal wiki with owner, review date, and exception process for any remaining inline requirements. Teams that migrate successfully often keep Report-Only headers in place indefinitely at lower strictness to catch regressions when new tags ship. Treat CSP as living configuration reviewed in the same cadence as TLS certificates and DNS audits described in our pre-launch security checklist . Executive Summary for Stakeholders Removing unsafe-inline is a cross-functional project touching security, engineering, and marketing. Executives should expect a phased timeline measured in weeks for mature sites, not hours. Budget for regression testing on checkout and analytics. The business outcome is reduced XSS blast radius and cleaner answers on security questionnaires—not a visible customer feature. Frame success as fewer CSP exceptions and stable enforcement without revenue-impacting breakage. Assign a single owner who can approve temporary Report-Only policies and coordinate vendor contacts for tag managers. Without ownership, CSP migrations stall at the first broken heatmap script. Revisit CSP after every major CMS plugin update because admin panels inject new inline scripts without developer review. A quarterly CSP checker appointment catches drift before auditors do. Operational security improves when findings from this guide feed a tracked remediation backlog with owners and due dates. Export scan results from the Vulnify dashboard , link tickets to specific URLs and tools used, and re-run the same checks after deploy to prove closure. Pair technical fixes with process updates—onboarding checklists, quarterly reviews, and change management—so the same misconfiguration class does not reopen after the next launch or vendor migration. Operational security improves when findings from this guide feed a tracked remediation backlog with owners and due dates. Export scan results from the Vulnify dashboard , link tickets to specific URLs and tools used, and re-run the same checks after deploy to prove closure. Pair technical fixes with process updates—onboarding checklists, quarterly reviews, and change management—so the same misconfiguration class does not reopen after the next launch or vendor migration. Operational security improves when findings from this guide feed a tracked remediation backlog with owners and due dates. Export scan results from the Vulnify dashboard , link tickets to specific URLs and tools used, and re-run the same checks after deploy to prove closure. Pair technical fixes with process updates—onboarding checklists, quarterly reviews, and change management—so the same misconfiguration class does not reopen after the next launch or vendor migration. Operational security improves when findings from this guide feed a tracked remediation backlog with owners and due dates. Export scan results from the Vulnify dashboard , link tickets to specific URLs and tools used, and re-run the same checks after deploy to prove closure. Pair technical fixes with process updates—onboarding checklists, quarterly reviews, and change management—so the same misconfiguration class does not reopen after the next launch or vendor migration. Operational security improves when findings from this guide feed a tracked remediation backlog with owners and due dates. Export scan results from the Vulnify dashboard , link tickets to specific URLs and tools used, and re-run the same checks after deploy to prove closure. Pair technical fixes with process updates—onboarding checklists, quarterly reviews, and change management—so the same misconfiguration class does not reopen after the next launch or vendor migration. Frequently Asked Questions What does CSP unsafe-inline mean? It allows inline scripts and event handlers to run without nonces or hashes. Browsers treat attacker-injected inline script the same as legitimate template code, which weakens XSS protections. Can I remove unsafe-inline without breaking Google Analytics? Often yes, by moving tags to external files, using nonce attributes on approved snippets, or adopting server-side tagging. Test in Report-Only mode before enforcement because legacy gtag snippets vary. What is the difference between nonce and hash in CSP? Nonces are per-response random tokens paired with script tags. Hashes fingerprint exact static script content. Nonces suit dynamic apps; hashes suit unchanging inline blocks like JSON-LD. Should I use Content-Security-Policy-Report-Only first? Yes for production changes. Report-Only logs violations without blocking users, letting you measure breakage on real traffic before switching the enforcing header. Does unsafe-inline in style-src matter for XSS? Style-based attacks are less common than script injection but still relevant in some browsers and contexts. Many teams tighten script-src first, then address style-src in a follow-up phase. How do I verify CSP after deployment? Use the Vulnify CSP checker on live URLs, confirm headers at the CDN edge, and spot-check critical flows in browsers with devtools console open for CSP violation reports. Does CSP replace input sanitization? No. CSP is defense in depth. You still must encode output, use framework auto-escaping, and fix stored XSS in application code. Related Guides Permissions-Policy vs Security Headers Pre-Launch Security Checklist (8 Free Checks) Mixed Content on HTTPS Sites: Find and Fix Insecure Assets WAF and CDN Detection: What It Means for Your Scans