Research

Google chose CSP.

And you should too.

Gmail, YouTube, Google Photos, Cloud Console and the Google Account all enforce a Content Security Policy today. So do Adyen, Klarna, American Express, PayPal, GitHub and Monzo. Every claim on this page is a live HTTP response header you can check yourself in ten seconds.

9+
Google properties enforcing
4.1%
XSS payouts, down from 30%
130+
Services, zero DOM-based XSS
The Decision

Why Google chose CSP

Google had a cross-site scripting problem, and it was expensive. Their own developer guidance states that XSS “consistently accounts for over 60% of payouts under Google's Vulnerability Reward Program”, and in the two years before 2016 they paid researchers over $1.2 million for XSS bugs alone. Fixing bugs one at a time was not working, because there was always another bug.

So they went looking for a control that would make the whole class of bug unexploitable, rather than a process for finding them faster. They picked Content Security Policy — and then they did something more interesting than adopting it.

They studied why everyone else's CSP was failing. Google analysed policies across more than a billion domains and found that 94.68% of policies attempting to restrict script execution could be bypassed, because 14 of the 15 most commonly allow-listed script domains contained something an attacker could abuse. Host allow-lists, the way almost everyone wrote CSP, simply did not work.

Google's response to “CSP as commonly deployed is broken” was not to abandon CSP. It was to write the spec change that fixed it.

That change is 'strict-dynamic', published in the paper CSP Is Dead, Long Live CSP! at ACM CCS 2016. It replaces the host allow-list with a cryptographic nonce: one unguessable token per page load, and only scripts carrying it may run. An attacker who injects a script tag cannot guess the token, so the script does not execute — regardless of which domains you trust.

Then Google deployed it across their own products, and left it there. It has been running ever since.

The Evidence

The headers, verified

This is what Google Cloud Console sends on every request. Not a recommendation in a blog post — the live policy on a product they charge money for.

console.cloud.google.com — HTTP response header
content-security-policy: script-src 'report-sample' 'nonce-Z17sjSYE92DoPDIvM0AHAg' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:; object-src 'none'; base-uri 'self'; report-uri https://csp.withgoogle.com/csp/CloudConsoleWeb
content-security-policy: require-trusted-types-for 'script'; report-uri https://csp.withgoogle.com/csp/CloudConsoleWeb

Three things in that header are worth pulling out. There is a nonce, so injected scripts cannot execute. There is Trusted Types, enforced, which closes DOM-based XSS at the API level. And there is a reporting endpoint, because a policy you are not monitoring is a policy you cannot maintain.

Every property below was read off a live response header, and every one of them answers the same command — provided that command follows redirects and identifies itself as a browser, for the reasons set out under the table. Each sends an enforcing Content-Security-Policy header unless noted.

Google property Script control Trusted Types Reporting
console.cloud.google.comNonce + strict-dynamicEnforcedYes
www.youtube.comNonce + strict-dynamicEnforcedYes
photos.google.comNonce + strict-dynamicEnforcedYes
calendar.google.comNonce + strict-dynamicEnforcedYes
accounts.google.comNonceEnforcedYes
mail.google.comNonceEnforcedYes
myaccount.google.comNonceEnforcedYes
drive.google.comNonceEnforcedYes
docs.google.comNonceEnforcedYes

Check any row yourself. It takes one command and no account:

Verify it yourself
curl -sIL -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/140.0.0.0" \
  https://www.youtube.com/ | grep -i content-security-policy

Both flags are load-bearing, and it is worth saying why rather than leaving them to be discovered. Most of these hosts answer a signed-out request with a redirect, so -L is what reaches the response carrying the policy. And two of them — calendar.google.com and myaccount.google.com — send no Content-Security-Policy header at all to a client that does not identify itself as a browser. Drop either flag and those two rows come back empty, and you conclude this page is wrong.

One honest note, because it is the sort of thing worth hearing from us rather than from someone correcting us. The www.google.com homepage runs its strict policy in report-only mode, not enforcing. Even Google stages a rollout on their highest-traffic property — which is exactly the workflow we recommend, and exactly why the reporting half of this matters as much as the enforcement half.

The Result

What it did to their XSS rate

The strongest argument for CSP is not that Google deployed it. It is what happened next.

Trusted Types — the require-trusted-types-for directive you can see in the headers above — is delivered as part of Content Security Policy. There is no Trusted Types without CSP. So this is CSP's scoreboard, in Google's own numbers:

2018

30% of all bug bounty payouts

Cross-site scripting was Google's single most expensive class of vulnerability, accounting for nearly a third of everything paid out under their Vulnerability Reward Program.

2023

4.1% of all bug bounty payouts

Every remaining report came from properties that had not yet migrated. Google reported no XSS at all — via bounty, in-the-wild attack, or internal research — on migrated properties over the preceding three years.

Scale

130+ services, zero DOM XSS

Google reported zero incidence of DOM-based XSS across every application migrated to Trusted Types since 2019 — a class of bug that previously made up more than half of the XSS reported to them.

A roughly 86% fall in Google's most expensive vulnerability class, delivered by a browser feature that ships as a Content Security Policy directive and costs nothing to run.

The Company

Who else uses CSP

Google is the most thoroughly documented deployment, but it is not the only organisation of its size running a policy of this shape. Every row below was read off a live response header, and the same command works on each of them.

Payments, banking and commerce

This is the group that matters most if you are working through PCI DSS 6.4.3 and 11.6.1, because these are the organisations with card data on the other side of the page.

Organisation What their policy uses
AdyenNonce + strict-dynamic + reporting
KlarnaNonce + strict-dynamic
MonzoNonce + strict-dynamic + reporting
American ExpressNonce + reporting
PayPalNonce + reporting
Stripedefault-src 'none' + script hashes + reporting
CoinbaseNonce + default-src 'none'
Barclaysdefault-src 'none'

Technology and platforms

Organisation What their policy uses
GitHubdefault-src 'none' — one of the tightest policies on the web
DropboxNonce + strict-dynamic + reporting
CloudflareNonce + default-src 'none'
MetaNonce
XNonce
LinkedIndefault-src 'none'
npmNonce + default-src 'none'
RedditNonce + default-src 'none'
DiscordNonce + script hashes
GOV.UKdefault-src 'self', base-uri 'none'

CSP adoption is also growing, not fading. The HTTP Archive's Web Almanac put CSP on 21.9% of sites in 2025, up from 18.5% in 2024 — a relative increase of roughly 18% in a single year.

Read It Properly

Reading the policy properly

Look at Google's header again and you will spot 'unsafe-inline', 'unsafe-eval' and a bare https:. Presented without context, those look like a policy full of holes. They are not, and the reason is worth understanding because it is the single most common way CSP gets misrepresented.

Ignored

'unsafe-inline'

Any browser that understands nonces ignores 'unsafe-inline' completely when a nonce is present. It is left in deliberately as a fallback for browsers too old to understand nonces at all. In a modern browser it does nothing.

Ignored

https: and http:

Any browser that understands 'strict-dynamic' ignores host expressions entirely. Same purpose: a graceful fallback for older browsers, inert in current ones.

Real

'unsafe-eval'

This one is live, and we are not going to pretend otherwise. Google took the pragmatic trade in some applications. Strict CSP's job is stopping injected script from executing, and it does that with the nonce whether eval is permitted or not.

This is the shape of nearly every argument that CSP does not work: describe the weakest possible deployment, or read a modern policy as though it were a 2015 one, and attribute the result to the standard rather than to the configuration. A firewall with an any–any rule does not work either. That is not an argument against firewalls.

Not Legacy

Still being built in 2026

The other common claim is that CSP is a decade-old standard that has been left behind. Browser engineering says otherwise — Chrome has shipped significant new CSP capability in the last two years, aimed squarely at script inventory and integrity.

Script hash reporting — the browser reports the SHA hash of every script it actually executed, so you can inventory real code from real sessions rather than guess from a crawl

URL and eval hashes in script-src, shipped November 2025, letting a policy pin exactly what may run and report the hashes needed to build that list

Trusted Types now present or enforced on roughly one in ten Chrome page loads, with Mozilla moving to support the standard and Meta and Microsoft deploying it too

Browser vendors do not spend engineering budget extending a standard they consider finished. See what a modern CSP can do →

The Point

What this means for you

Strip Google's deployment down to its architecture and there are three moving parts:

An enforcing strict policy, so unauthorised script cannot execute

A second, report-only policy running alongside it, keeping a live inventory of what actually loads

A reporting endpoint collecting violations from real browsers, in real sessions, at scale

You can read all three off the headers on this page. Google runs both policies simultaneously and sends the reports from both to an endpoint they built and operate themselves.

Google is not a Report URI customer, and we are not going to imply otherwise. They built their own endpoint. The point is that when one of the best security engineering organisations in the world decided how to secure the browser half of their applications, this is the architecture they arrived at — and the only part of it you would otherwise have to build is the part we already run.

The policy is yours. It sits in your response headers, enforced by every browser that visits you, and it keeps working whether or not you have a relationship with us. What we do is the piece Google had to build for themselves: collect the reports, turn them into a policy you can actually maintain, keep verified copies of the scripts that ran, and alert you when any of it changes.

Nothing routes through us. Nothing runs on your pages. If we disappeared tomorrow, your policy would carry on blocking exactly what it blocked yesterday. See how that maps to PCI DSS 6.4.3 and 11.6.1 →

FAQ

Frequently asked questions

Both, simultaneously. Google Cloud Console, YouTube, Google Photos, Google Calendar, Gmail, Google Drive, Google Docs and the Google Account all send an enforcing Content-Security-Policy header, and most send a second report-only policy alongside it to keep an inventory of what loads. The www.google.com homepage is the exception: its strict policy runs in report-only mode.

No, and we will not imply otherwise. Google collects its own CSP reports at csp.withgoogle.com, an endpoint they built and operate in-house. The point of this page is the architecture they chose, not the vendor: an enforcing strict policy, a report-only policy running alongside it, and a reporting endpoint collecting violations from real browsers. The only part of that you would otherwise have to build yourself is the part we run.

No. Any browser that understands nonces ignores unsafe-inline entirely when a nonce is present, and any browser that understands strict-dynamic ignores host expressions like https:. Both are deliberate fallbacks for browsers too old to understand the modern keywords, and both are inert in current browsers. Reading them as holes is the single most common way a modern CSP gets misrepresented.

Cross-site scripting accounted for 30% of all Google Vulnerability Reward Program payouts in 2018. In 2023 it was 4.1%, and every remaining report came from properties not yet migrated to Trusted Types, which is delivered as a CSP directive. Google also reported zero DOM-based XSS across more than 130 services migrated since 2019.

Chrome shipped script hash reporting and then URL and eval hashes in script-src in November 2025, both aimed at script inventory and integrity. Trusted Types is now present or enforced on roughly one in ten Chrome page loads. CSP adoption grew from 18.5% of sites in 2024 to 21.9% in 2025. Browser vendors do not extend a standard they consider finished.

No, and nobody serious claims otherwise, including Google, whose own guidance calls strict CSP a defence-in-depth technique rather than a substitute for fixing bugs. A policy decides what may execute; you still need to know what actually ran, keep a copy of it, and be told when it changes. That is the part we do.

Run the policy Google runs. Skip building the endpoint.

Set one header and reports arrive from your first visitor. No agent on your pages, nothing in your request path.