Reference
Content-Security-Policy directives
Content Security Policy Level 3 defines twenty-three directives, in five groups: sixteen fetch directives that decide where scripts, styles, images, frames and connections may load from, two document directives, two navigation directives, two reporting directives of which report-uri is deprecated, and webrtc. Most fetch directives fall back to default-src when absent; the non-fetch directives never do, which is why default-src 'none' still allows the page to be framed by anyone. upgrade-insecure-requests is defined by a separate specification.
| Directive | Group | What it controls | Falls back to | In a meta policy |
|---|---|---|---|---|
| default-src | Fetch | The fallback for every other fetch directive that is not set. | Nothing: it is the fallback. | Allowed |
| child-src | Fetch | Frames and workers, through the fallback lists of frame-src and worker-src. | default-src | Allowed |
| connect-src | Fetch | URLs contacted from script: fetch(), XMLHttpRequest, WebSocket, EventSource and sendBeacon. | default-src | Allowed |
| font-src | Fetch | Fonts loaded with @font-face. | default-src | Allowed |
| frame-src | Fetch | The URLs the page may load into its own frames and iframes. | child-src, then default-src | Allowed |
| img-src | Fetch | Images and favicons. | default-src | Allowed |
| manifest-src | Fetch | Application manifests. | default-src | Allowed |
| media-src | Fetch | Audio, video and text tracks. | default-src | Allowed |
| object-src | Fetch | Plugin content loaded by object and embed. | default-src | Allowed |
| script-src | Fetch | Scripts, including inline scripts, inline event handlers and string evaluation such as eval(). | default-src | Allowed |
| script-src-elem | Fetch | Script elements only, inline and external. | script-src, then default-src | Allowed |
| script-src-attr | Fetch | Inline event handler attributes such as onclick. | script-src, then default-src | Allowed |
| style-src | Fetch | Style sheets, inline style elements and style attributes. | default-src | Allowed |
| style-src-elem | Fetch | Style elements and linked style sheets only. | style-src, then default-src | Allowed |
| style-src-attr | Fetch | Inline style attributes only. | style-src, then default-src | Allowed |
| worker-src | Fetch | Scripts run as Worker, SharedWorker or ServiceWorker. | child-src, then script-src, then default-src | Allowed |
| base-uri | Document | The URLs a base element may set as the document's base URL. | None | Allowed |
| sandbox | Document | Applies iframe-style sandbox restrictions to the page itself, with the same allow- keywords. | None | Not supported |
| form-action | Navigation | The URLs forms may submit to. | None | Allowed |
| frame-ancestors | Navigation | Which pages may embed this page in a frame; the modern replacement for X-Frame-Options. | None | Not supported |
| report-uri | Reporting | A URL that receives violation reports. Deprecated in favour of report-to, and ignored when report-to is present. | None | Not supported |
| report-to | Reporting | The name of a reporting endpoint, defined through the Reporting API, that receives violation reports. | None | Allowed |
| webrtc | Other | Whether WebRTC connections may be established: 'allow' or 'block'. | None | Allowed |
| upgrade-insecure-requests | Defined elsewhere | Rewrites the page's http:// subresource URLs to https:// before fetching them. | None | Allowed |
How the fallbacks decide what a short policy allows
A fetch directive that is absent is not "allow everything": the browser walks its fallback list until it finds a directive that is present. `script-src-elem` falls back to `script-src`, then to `default-src`; `worker-src` goes through `child-src` and `script-src` before `default-src`; `frame-src` goes through `child-src`.
That is what makes `default-src 'self'` a meaningful one-line policy: every fetch directive the policy does not mention inherits it.
The document, navigation and reporting directives have no fallback. `default-src 'none'` does not restrict `form-action`, `base-uri` or `frame-ancestors`, so a strict-looking policy can still let any site frame the page or let an injected base element redirect every relative URL.
The split `-elem` and `-attr` directives exist so a policy can allow external scripts while forbidding inline event handlers, which a single `script-src` cannot express without `'unsafe-inline'`.
Several policies can apply at once — two `Content-Security-Policy` headers, or a header and a meta element — and each is enforced on its own. A request has to pass every one of them, so adding a second policy can only restrict further; it can never loosen the first.
What a meta element can and cannot carry
A policy can be delivered in the `Content-Security-Policy` response header or in a `<meta http-equiv>` element. The meta form is read only from the point the parser reaches it, so anything loaded before it is not covered.
CSP Level 3 excludes three directives from the meta form: `frame-ancestors`, `sandbox` and `report-uri`. The report-only variant of the header cannot be delivered in a meta element at all.
A site that relies on a meta policy for clickjacking protection therefore has none: `frame-ancestors` only works as a header.
What a scan reads in the policy
`security.csp` reads the `Content-Security-Policy` header of the entry page, or `Content-Security-Policy-Report-Only` when that is all the site sends. A missing policy is reported as a failure.
It then flags `'unsafe-inline'` and `'unsafe-eval'` wherever they appear, and a `*` source in `default-src` or `script-src`. A policy without those is reported as present; the scan does not evaluate each directive of the table against the page's real resources.
Framing protection is read separately by `security.x_frame_options`, which looks for the `X-Frame-Options` header. It does not read `frame-ancestors`, so a site protected only by that directive is reported as missing the header although browsers that support CSP do enforce the protection.
A policy delivered only in a meta element is not read by these checks, which look at response headers.
Frequently asked questions
- Does default-src apply to frame-ancestors?
- No. frame-ancestors, form-action, base-uri, sandbox and the reporting directives have no fallback. A policy of default-src 'none' still lets any site frame the page unless frame-ancestors is set.
- Can I set frame-ancestors in a meta tag?
- No. CSP Level 3 does not support frame-ancestors, sandbox or report-uri in a policy delivered by a meta element. Framing protection has to be sent as a response header.
- Should I still use report-uri?
- It is deprecated in favour of report-to, and ignored when report-to is present. The specification suggests sending both for compatibility with browsers that do not support report-to yet.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website