Skip to content
AZ Tools

CSP Hash Generator

Compute the sha256 / sha384 / sha512 base64 hash an inline <script> or <style> block needs to be whitelisted by a Content-Security-Policy.

Algorithm
Target directive

Paste something to hash.

The browser hashes the exact bytes of the inline element. Whitespace, indentation, and line endings all count.

How to use

  1. Paste the script body (everything between <script> and </script>) or the style body.
  2. Pick the algorithm (sha256 is enough for almost everyone; 384/512 if your policy mandates them).
  3. Copy the resulting 'sha256-…' token into the right -src directive.

About this tool

Show

Paste the exact contents of an inline script or style and get back the 'sha256-…' token that Content-Security-Policy accepts as an allow-list entry. SHA-256, SHA-384 and SHA-512 are all valid in CSP; the digest is taken over the UTF-8 bytes and base64-encoded, which is precisely what the browser does at parse time before comparing.

Because it is a byte-for-byte comparison, everything that changes bytes changes the hash. Paste the element's text content only — no <script> tags, no surrounding indentation that is not really there. A file saved with CRLF line endings hashes differently from the same file with LF, and a trailing newline your editor added silently is a different script as far as CSP is concerned. When a hash you are sure about does not match, the culprit is almost always whitespace at one end or a line-ending conversion somewhere in the build.

There is a policy-level behaviour that surprises people more than the hashing does. Adding any hash or nonce to script-src makes the browser ignore 'unsafe-inline' in the same directive — the fallback exists only for browsers too old to understand hashes. So you cannot list a hash "as well as" keeping inline scripts working; the moment the first hash appears, every inline script needs one. That is the intended migration path, and it is also why a policy that half-adopts hashes breaks a page that worked a minute earlier.

Hashes also cannot cover everything inline. An onclick= attribute and a javascript: URL are inline script, but they are not elements with text content, so no hash matches them — CSP Level 3 added 'unsafe-hashes' for exactly that case, and the name is a fair warning. Move handlers into a hashed script block if you can. The generator runs entirely in your browser through the Web Crypto API, so a script you are not ready to publish is not published by hashing it.

Frequently asked questions

Whitespace and newlines matter?

Yes — the browser hashes the literal bytes of the element. A trailing newline or a different indentation will invalidate the hash. Paste exactly what's between the tags.

Should I always use sha512?

No. sha256 is the de-facto baseline; sha384/sha512 are only required if your policy or auditor specifies them. Longer digests don't add real security here — the threat model assumes the inline content is what you authored.

Hash or nonce — which should I use?

A hash suits a script whose contents never change, because it can be computed once and pasted into a static header. A nonce suits anything generated per request, since it is a fresh random value the server writes into both the header and the tag on every response. What a nonce must never be is reused or predictable — a nonce that survives across responses allows exactly the injection the policy exists to stop.

My hash stopped matching after a deploy. What changed?

Almost certainly the bytes of the script did. A minifier that renames a variable, a build step that rewrites a template, a change from tabs to spaces, or an editor adding a final newline all produce a different digest even though the code behaves identically. Generate the hash from the exact text that ships, as a build step, rather than from the source you edit.

Related tools