Fix guide · high · csp_unsafe_inline_scripts

CSP allows 'unsafe-inline' in script-src

What this rule means

Your Content-Security-Policy header includes 'unsafe-inline' in script-src (or in default-src with no script-src override). Any reflected or stored XSS executes immediately — the CSP provides essentially no protection against script injection.

Why it matters

CSP exists to mitigate XSS. The way it does that is by refusing to run inline <script>...</script> blocks and event handlers (onclick="...") that an attacker has injected. 'unsafe-inline' switches that protection off — inline scripts run again, just like in a pre-CSP world. The directive name was chosen specifically to flag the trade-off.

The pattern shows up most often because a build tool needed it (lots of legacy React/Vue setups inline initial state via <script>window.__INITIAL_STATE__ = ...</script>) and no one revisited it after migrating to a hash-based or nonce-based approach.

How to fix it

Replace inline scripts with one of three safer patterns, then drop 'unsafe-inline' from your CSP.

1. Nonces. Generate a random nonce per request (server-side), inject it into the CSP header AND every legitimate inline script tag. Attacker-injected inline scripts won't have the nonce and will be blocked.

// On every request:
const nonce = crypto.randomBytes(16).toString("base64");
res.setHeader(
  "Content-Security-Policy",
  `default-src 'self'; script-src 'self' 'nonce-${nonce}'`,
);
// In your HTML template:
// <script nonce="${nonce}">window.__INITIAL_STATE__ = ...</script>

2. Hashes. If your inline script content is static, compute its SHA-256 hash at build time and pin the hash in CSP. The browser refuses to run any inline script whose hash doesn't match.

Content-Security-Policy: script-src 'self' 'sha256-AbCdEf...';

3. Externalize. Move the inline script body into a separate .js file served from your origin. The CSP script-src 'self' then permits it without nonces or hashes.

After deploying, validate at csp-evaluator.withgoogle.com — paste your CSP, look for green badges on script-src.

Full guide: /blog/csp-bypass-vibe-coded.

Did vibecheck flag this on your app?

If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.

Run another inspection