Fix guide · info · csp_inline_script_hash_pinned
Inline scripts correctly pinned by CSP hash (positive signal)
Your CSP includes 'sha256-...' hash entries that match the inline scripts on the page. This is the recommended pattern for serving inline JSON-LD or small bootstrap code under a strict CSP — surfaced here as a positive confirmation that the build pipeline is doing the right thing.
Why it matters
Hash-based CSP is the most secure way to permit inline scripts. The mechanism:
- At build time, you compute
sha256(inline-script-content)for every inline<script>block on every page. - You ship a CSP header listing all those hashes in
script-src:'sha256-AbCdEf...'. - At runtime, the browser computes the hash of each inline script before executing it. If the hash matches an entry in the policy, the script runs. If not, it's blocked.
The security guarantee: an attacker who injects a NEW inline script (via XSS, reflected input, etc.) cannot pre-compute a matching hash without controlling the build. Even 'unsafe-inline' is bypassed if hashes are also present (newer CSP versions; older browsers treat hashes as additive).
This finding fires when:
- Your CSP includes one or more
'sha256-...'entries. - All inline scripts on the served page match an entry.
- No inline script is blocked.
This is a positive signal. We surface it so you know your build pipeline is producing a working hash-pinned CSP — easy to break by accident later.
How to fix it
No action required — your CSP and your content are in sync.
To keep it that way:
- Make hash regeneration a build step that runs on every deploy. Don't ship CSP changes from a separate path than content changes.
- Vibecheck's source repo includes
scripts/build-csp.tsas a reference — adapt it to your stack if you don't already have a generator. - Periodically inspect the CSP header you're shipping: it should grow when you add inline scripts and shrink when you remove them. If it's static, it's drifting.
Edge case to watch: Cloudflare Pages has a 16 KB header limit. Sites with many inline scripts (vibecheck itself ships ~320 JSON-LD blocks across ~30 pages) can exceed it. If you hit the limit, options are: (a) move inline content to external files, (b) use a Pages Function to set the header dynamically per-route, or (c) accept 'unsafe-inline' with the trade-off documented (vibecheck did this — see /blog/csp-bypass-vibe-coded for our reasoning).
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