Syllabus Lesson 64 of 156 · Content Security Policy and framing
Content Security Policy and framing

What CSP is

Why it matters In Module 10 you saw how one unescaped comment can put an attacker's script on a page. Escaping is the first line of defence, but one missed spot is enough. Content Security Policy is a second line: even if a script slips into your HTML, the browser refuses to run it. For visitors, that means a bug on your site is much less likely to become their stolen session or their data sent somewhere else.

Think of a guest list at the door of a party. The host writes down who may come in. The door staff do not care how convincing a stranger looks: no name on the list, no entry. A Content Security Policy is a guest list for everything a page loads and runs.

Content Security Policy (CSP): a response header, Content-Security-Policy, in which a site tells the browser where scripts, styles, images, frames and other resources may come from. The browser blocks anything not on the list and logs a message in the DevTools console.

How a policy is built

A policy is a list of directives separated by semicolons. Each directive is a name followed by its sources, separated by spaces.

Content-Security-Policy: default-src 'self'; img-src 'self' https://img.example; object-src 'none'

Directive: one rule for one kind of resource, such as script-src (scripts), style-src (style sheets), img-src (images), font-src, connect-src (fetch and similar requests from scripts), frame-src (iframes inside your page) and object-src (old plug-ins).

Source: one entry in a directive. 'self' means your own origin (same scheme and host). https://cdn.example means that one host. *.cdn.example means its subdomains. https: means any HTTPS address. * means almost anything. 'none' means nothing at all. Keywords such as 'self' must keep their single quotes; host names must not have them.

The fallback rule

default-src is the guest list used for any fetch directive you did not write. In the header above, scripts and styles fall back to 'self', while images get their own list. Three important directives never fall back: frame-ancestors (who may frame your page, Lesson 68), base-uri (what a <base> tag may point to) and form-action (where forms may submit). If you leave those out, they are simply not restricted.

Inline code is the big one. Without help, a policy with script-src 'self' blocks every <script>...</script> written in the page and every onclick= style attribute. That is exactly what you want against injection, and it is why sites need a way to allow their own inline scripts (Lesson 66).

Reading a real header: this site's

Here is the script part of the policy learn.floati.life sends (checked October 2026), shortened:

default-src 'self'; base-uri 'self'; object-src 'none';
script-src 'self' 'nonce-RANDOM' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval'
           https://cdnjs.cloudflare.com https://unpkg.com https://esm.run https://cdn.jsdelivr.net blob:
  • default-src 'self': anything not listed loads only from this site.
  • object-src 'none' and base-uri 'self': no plug-ins, and an injected <base> tag cannot quietly redirect relative links.
  • 'nonce-RANDOM': a fresh random value on every page load. Only inline scripts carrying it may run.
  • 'unsafe-inline': looks alarming, but browsers that understand nonces ignore it once a nonce is listed. It is kept only for very old browsers.
  • 'unsafe-eval': an honest trade-off. The in-browser Python and on-device AI need it, so the site accepts that risk and documents why.
  • A short list of named script hosts, rather than https: or *.

Reading policies this way, line by line, asking "what does this let in, and why?", is the skill this module builds.

A common misconception: "with CSP I do not need to escape". CSP is a seat belt, not brakes. A policy with a gap, or a page that allows 'unsafe-inline' without nonces, still runs injected code. Escape first, then add CSP.

Try it Open DevTools on any site, go to the Network tab, reload, click the first (document) request and look under Response Headers for content-security-policy. Many large sites send one; many small ones send none. Then open the Console: blocked resources show up there as CSP messages.

Recap

  • CSP is a guest list header: the browser refuses resources and inline code the policy does not allow.
  • Directives cover kinds of resource; default-src fills in for missing fetch directives, but frame-ancestors, base-uri and form-action never fall back.
  • Blocking inline scripts is the heart of CSP against injection; nonces let your own inline scripts through.
  • CSP backs up escaping; it does not replace it.

Spotted a problem in this lesson? Report it

Code · runs in your browser
Output