Content Security Policy: How a browser rule limits injected code, and where it fails
A Content Security Policy is a browser rule that limits which code a web page can run. Here is how it works, why allowlists leak, and what the ChatGPT share-link flaw showed.

A Content Security Policy (CSP) is a rule that a website hands to your browser. It lists where the page may load code and other resources from, and the browser refuses everything else. Its main job is to limit cross-site scripting (XSS), an attack in which a stranger gets their own JavaScript to run inside a trusted site.
CSP is a backstop, not a lock on the front door. It is meant to keep damage small when something else has already gone wrong.
A guest list for code on the page
Picture a building with a doorman and a guest list. Anyone not on the list is turned away, even if they walk in behind a resident. A CSP works like that list, and the browser is the doorman.
The site sends the list in an HTTP response header called Content-Security-Policy. A simple one looks like this:
Content-Security-Policy: default-src 'self'; img-src 'self' example.com
Read it in plain words: by default, load things only from this site ('self'), and allow images from this site and example.com. Each rule is called a directive. Mozilla’s developer documentation lists others, including script-src for JavaScript, object-src for plug-in content and frame-ancestors for controlling who may embed the page.
What a policy blocks by default

Once a policy sets default-src or script-src, the browser blocks several things unless they are explicitly allowed. Mozilla’s documentation names inline <script> blocks, inline event handlers such as onclick, javascript: URLs, and eval().
This matters because most XSS attacks work by slipping an inline script into a page. With inline code blocked, a plain injected <script> tag does nothing.
Sites can switch these protections off with keywords such as 'unsafe-inline' and 'unsafe-eval'. Mozilla advises against them, because they remove protection against the most common attacks.
Allowlists versus nonces
There are two ways to say which scripts are trusted. The older way is an allowlist of hosts, for example script-src www.googleapis.com. Any script served from that host is allowed.
The newer way is a strict CSP. The server generates a random value called a nonce for every response. It puts the nonce in the header and on each trusted script tag:
Content-Security-Policy: script-src 'nonce-{RANDOM}'; object-src 'none'; base-uri 'none'
An attacker who injects a script cannot guess the nonce, so the browser skips it. Sites with static pages can use hashes instead. The header then lists a SHA-256 fingerprint of each trusted script.
Google’s web.dev guidance says nonces should be unpredictable, at least 128 bits, and new for each response. It also describes 'strict-dynamic'. This keyword lets a trusted script load further scripts, which makes third-party widgets easier to use. Mozilla notes the trade-off: if a trusted script builds script elements from attacker-controlled input, the CSP will not stop them.
Why allowlists leak
Allowlists have a structural weakness. They trust a whole host, not a single script. If that host serves anything an attacker can steer, the allowlist becomes a way in.
One well-known example is JSONP, an older technique in which a server wraps data in a function call so that a page can load it as a script. If the attacker controls the name of that function, a trusted address will return code the attacker chose.
Google researchers made this case in a 2016 paper, CSP Is Dead, Long Live CSP!, which web.dev cites. The web.dev guide says allowlist policies can be bypassed in most configurations, and it cites a case where integrating one analytics product required 187 Google domains on an allowlist.
This is why Google’s guidance recommends nonce or hash policies over host lists.
The ChatGPT share-link flaw as a case study
Security firm Parameter described a chain of weaknesses in ChatGPT that let a malicious public share link run an attacker’s JavaScript in a victim’s logged-in session. Our news report covers the full sequence.
The part that matters here is the CSP. According to Parameter, ChatGPT’s policy blocks inline scripts but allows YouTube. The attacker used a YouTube oEmbed response in JSONP form to run code inside an injected frame anyway. That is the allowlist problem described above, in a live product.
Parameter also argues the CSP was not the root cause. In its account, the real fault was a message listener that accepted messages from a sandboxed frame without checking who sent them, and then inserted HTML without sanitizing it. Blocking only the YouTube endpoint, it says, would have left the HTML injection path open.
OpenAI fixed the flaw on October 26 and paid a $5,000 bounty, according to The Hacker News as cited in our report.
Limits of CSP and what to watch
The case shows what CSP can and cannot do. It narrows what injected code can do, but it does not fix the bug that allowed the injection. Mozilla’s documentation calls CSP a defense in depth that should complement input sanitization, not replace it.
Other limits listed by Mozilla and Google:
- Nonces need a fresh value per response, so fully static HTML is harder to serve.
- Hashes must be recalculated whenever a script changes.
- A policy delivered in a
<meta>tag does not support every feature, including report-only mode andframe-ancestors. - Keywords such as
'unsafe-inline'undo much of the protection.
Teams can test a new policy without breaking anything. The Content-Security-Policy-Report-Only header enforces nothing and sends violation reports to an endpoint, so a site can see what a stricter rule would block before it turns the rule on.
Mozilla also describes Trusted Types, enabled with require-trusted-types-for 'script'. With it, risky browser functions such as innerHTML reject plain strings and accept only objects made by an approved policy. That targets the kind of unsanitized HTML insertion Parameter describes, though Mozilla warns a policy that does not truly sanitize gives no protection.
AI products make this more pressing. Chat apps now render charts, previews and embedded apps from content that anyone can share, and each of those features is a place where untrusted content meets a trusted page. For readers, the practical lesson is narrow. A CSP is worth having, but a policy that trusts a whole host can be only as strong as the least careful endpoint on that host.
Sign Up for the Daily AI Pulse
One email a day. All the stories that matter.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Daniel ReedAI Research, Safety & Ethics AnalystDaniel Reed currently works as an AI Research, Safety & Ethics Analyst at Aiholics, writing about how changes in artificial intelligence are affecting and will affect scholarship,…
You may also like

Oracle wants the database, not the AI agent, to enforce your security rules

GPU confidential computing: How AI workloads stay encrypted while a GPU runs them

Cloud marketplace commit drawdown: How companies pay for AI tools with credits they already own
