Fix guide · high · csp_unsafe_inline_scripts
CSP allows 'unsafe-inline' in script-src
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