Safety
CSP script-src-elem vs script-src for Public Sites
March 11, 2023
CSP script-src-elem vs script-src for public sites is a split allowlist versus the combined one. script-src-elem governs <script> elements (src and inline script blocks). script-src-attr governs event-handler attributes like onclick. script-src is the shorthand that fills both when you omit the split directives, and it can still feed worker-src fallback. A tight script-src-elem does not lock inline handlers. unsafe-inline on script-src still weakens both. RoastMyOpsec grades CSP quality overall. It does not score missing script-src-elem as a standalone F, does not compare nonces to every tag, and does not exploit XSS.
The practical difference
Use script-src if you want one list for tags and handlers. Split into script-src-elem and script-src-attr when you can nonce or hash tags but still need to kill inline handlers. worker-src is workers, not <script>. default-src is the floor if you name neither.
GTM and CMS themes that inject onclick= need the attr half, not a looser elem half.
How to choose a script policy
Brochure with a nonce'd loader: script-src 'nonce-...' 'strict-dynamic' (or hashes) and no unsafe-inline. Need to allow CDN <script src> but forbid onclick: script-src-elem with hosts/nonces, script-src-attr 'none'. Report-Only first. See nonces vs hashes and default-src vs named directives.
| Directive | What it allows | Does not cover | Takeaway |
|---|---|---|---|
| script-src | Tags and handlers (shorthand) | A split you did not set | Usual brochure start |
| script-src-elem | <script> elements | onclick= and friends | Pin tags; lock attrs separately |
| script-src-attr | Event-handler attributes | <script src> | Prefer 'none' |
| worker-src | Worker scripts | Page <script> | See worker-src vs script-src |
When the split still wins
script-src-elem wins when tags can be nonce'd but leftover HTML handlers cannot. script-src still wins as one list for a simple brochure. Missing the split is not a finding if script-src is already tight. Pair with style-src vs unsafe-inline if the CMS also inlines CSS.
What the roast can prove
CSP quality signals on the landing header can surface. Missing script-src-elem is not scored as its own finding. Confirm which half actually applies. Pair with Report-Only until enforcing will not break the theme.
Common mistakes
The first mistake is script-src-elem 'self' with script-src still 'unsafe-inline'.
The second mistake is treating script-src-elem as coverage for onclick=.
The third mistake is splitting directives and forgetting worker-src.
Free audit the URL you own
RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.
Free audit nowFAQ
- Does script-src-elem replace script-src?
- No. It only covers <script> elements. Handlers are script-src-attr. The shorthand script-src fills both if you omit the split.
- Should brochure sites set script-src-elem?
- Only if you need a different allowlist than handlers. A tight script-src is enough. Missing the split is not a roast F.
- Does RoastMyOpsec score script-src-elem?
- No. It grades CSP quality overall and does not treat script-src-elem as the only script check.