# script-src-elem (/en/docs/web-security/policies/content-security-policy/directives/script-src-elem)



The `script-src-elem` directive in a Content Security Policy (CSP) controls which scripts can load through a `<script>` element, whether the element points to an external file or holds an inline script block. It does not cover inline event handler attributes like `onclick`, those belong to [`script-src-attr`](/en/docs/web-security/policies/content-security-policy/directives/script-src-attr). Use `script-src-elem` when you want a different rule for `<script>` tags than for handlers.

A minimal safe policy for this directive, nonce-based rather than a host allowlist:

```http
Content-Security-Policy: script-src-elem 'nonce-{RANDOM}' 'strict-dynamic'
```

## Fallback chain [#fallback-chain]

`script-src-elem` falls back to [`script-src`](/en/docs/web-security/policies/content-security-policy/directives/script-src), then to [`default-src`](/en/docs/web-security/policies/content-security-policy/directives/default-src). If you do not set `script-src-elem`, `<script>` elements are checked against `script-src`, and if that is also absent, against `default-src`. Setting `script-src-elem` fully replaces `script-src` for `<script>` elements.

Because the broader `script-src` already covers script elements, most policies never need `script-src-elem`. Reach for it only when you want script elements and inline handlers to follow separate rules.

## Values [#values]

`script-src-elem` takes the same value kinds as `script-src`, or `'none'`.

| Value              | Status  | Description                                                                           |
| ------------------ | ------- | ------------------------------------------------------------------------------------- |
| `'none'`           | ✅ Good  | Blocks every `<script>` element. Used alone.                                          |
| `'self'`           | ✅ Good  | Script elements from your own origin only.                                            |
| Host source        | ✅ Good  | A specific host such as `https://cdn.example.com`.                                    |
| `https:`           | ✅ Good  | Any origin over TLS. Very broad for scripts.                                          |
| `data:`            | ❌ Risky | Attacker-controlled `data:` URLs execute as script.                                   |
| `blob:`            | ❌ Risky | `blob:` URLs execute as script, an XSS vector.                                        |
| `'nonce-...'`      | ✅ Good  | Matches a `<script>` element carrying the same `nonce` attribute.                     |
| `'sha256-...'`     | ✅ Good  | Digest of an exact inline block or external file.                                     |
| `'strict-dynamic'` | ✅ Good  | Trust flows from nonce or hash allowed elements; host and scheme sources are ignored. |
| `'report-sample'`  | ✅ Good  | Adds the first 40 characters of blocked inline code to reports.                       |
| `'unsafe-inline'`  | ❌ Risky | Allows every inline `<script>` block, including injected ones.                        |

It accepts:

* [Keyword sources](/en/docs/web-security/policies/content-security-policy/values/csp-keywords) such as `'self'`, `'unsafe-inline'`, and `'strict-dynamic'`.
* A [nonce or hash](/en/docs/web-security/policies/content-security-policy/values/csp-hashes-nonce) to allow specific inline or external script elements.
* A [host source](/en/docs/web-security/policies/content-security-policy/values/csp-host-source) such as `https://cdn.example.com`.
* A [scheme source](/en/docs/web-security/policies/content-security-policy/values/csp-scheme-source) such as `https:`.

Nonces and hashes apply here just as they do on `script-src`. A nonce on a `<script>` element matches only when the element carries the same `nonce` attribute, and a hash matches the exact text content of an inline block.

## Examples [#examples]

Allow same-origin script elements and a CDN, while a nonce admits one inline block:

```http
Content-Security-Policy: script-src-elem 'self' https://cdn.example.com 'nonce-r4nd0m'
```

## Common use [#common-use]

A typical use is to allow your own scripts and a small set of trusted hosts for `<script>` elements, then control handlers separately with [`script-src-attr`](/en/docs/web-security/policies/content-security-policy/directives/script-src-attr); [how the two directives split script-src](/en/blog/script-src-elem-vs-script-src-attr) walks through the whole split with a worked example. As with `script-src`, the strong pattern is a nonce or hash plus `'strict-dynamic'` rather than a host allowlist, see the [strict-dynamic guide](/en/blog/strict-dynamic-csp) and the [nonce setup guide](/en/blog/csp-nonce-setup).

## Security notes [#security-notes]

`script-src-elem` blocks injected `<script>` tags that do not match the source list. Adding a nonce or hash makes `'unsafe-inline'` ignored, which is what stops an attacker from injecting an inline `<script>` block.

* `'unsafe-inline'` allows any inline `<script>`, including injected ones. Replace it with a nonce or hash, see [why to drop unsafe-inline](/en/blog/unsafe-inline-csp).
* Compute hashes for static inline blocks with the [hash generator](/tools/csp-hash), and check the resulting policy with the [CSP evaluator](/tools/csp-evaluator).

## Known bypasses and risks [#known-bypasses-and-risks]

The host allowlist weakness applies here too: an open redirect or JSONP endpoint on an allowed origin can load arbitrary script through a `<script>` element. `'strict-dynamic'` removes the allowlist from the decision and trusts only nonce or hash allowed elements and the scripts they create.

A subtle risk is forgetting that `script-src-elem` does not cover handlers. If you tighten `script-src-elem` but leave `script-src` (or `default-src`) permissive, inline `onclick=` handlers may still run, because they resolve through [`script-src-attr`](/en/docs/web-security/policies/content-security-policy/directives/script-src-attr).

## Recommendation [#recommendation]

Set the strict, nonce-based policy on `script-src` and let `<script>` elements inherit it through the fallback:

```http
Content-Security-Policy:
    script-src 'nonce-{RANDOM}' 'strict-dynamic';
    object-src 'none';
    base-uri 'none'
```

This is the strict CSP that the [OWASP CSP cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html) and [web.dev](https://web.dev/articles/strict-csp) recommend, and it covers script elements without a separate `script-src-elem`. Set `script-src-elem` only when elements and inline handlers genuinely need different rules, and keep it nonce or hash based rather than a host allowlist.

## Reporting [#reporting]

A blocked `<script>` element produces a [csp-violation report](/en/docs/web-security/reporting-api/reports/csp-violation) with `script-src-elem` as the effective directive. Add `'report-sample'` to include a short sample of the blocked content. CentralCSP collects these reports and uses CSP hash reporting to build a [script inventory](/platform/supply-chain) of every script element on your pages.

## Browser support [#browser-support]

Widely supported across current browsers.

## See also [#see-also]

* [script-src](/en/docs/web-security/policies/content-security-policy/directives/script-src)
* [script-src-attr](/en/docs/web-security/policies/content-security-policy/directives/script-src-attr)
* [default-src](/en/docs/web-security/policies/content-security-policy/directives/default-src)
* [Nonces and hashes](/en/docs/web-security/policies/content-security-policy/values/csp-hashes-nonce)
* [CSP evaluator](/tools/csp-evaluator)

## Sources [#sources]

* [MDN, CSP script-src-elem](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src-elem)
* [W3C, Content Security Policy Level 3](https://www.w3.org/TR/CSP3/)
* [web.dev, Mitigate XSS with a strict CSP](https://web.dev/articles/strict-csp)
* [OWASP, Content Security Policy cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html)
