The State of Web Security 2026
What the ismycodesafe scanner found on 2,211 public websites in May 2026: security headers, cookies, script integrity and Content-Security-Policy, with the method and the limits spelled out.

In May 2026 we ran the ismycodesafe scanner against 2,211 public websites. After throwing out failed fetches, bot-protection screens and error pages, 933 responses were left to measure. On 855 of them, 92 percent, nothing in the response headers limited which scripts a browser may run.
Correction, October 2026: an earlier version of this page reported results for 500 websites scanned from January to April 2026. We could not trace that dataset back to raw scan data, so every figure from it has been removed. The numbers below come from one batch, can be reproduced from the raw file, and each one states what it is counted out of.
How the sample was built
The 2,211 sites came from seven buckets:
| Bucket | How the sites were picked | Sites scanned |
|---|---|---|
| Long tail | Sample from the Tranco top-1M list, ranks 100,000 to 1,000,000 | 1,645 |
| Mid | Tranco ranks of roughly 10,000 to 120,000 | 169 |
| Top global | Tranco top 500 | 149 |
| Education | University domains (.edu, .edu.au, .edu.cn, .ac.uk, .ac.jp) found in the Tranco list | 75 |
| Norwegian | Hand-picked Norwegian sites | 74 |
| SaaS | Hand-picked software companies | 50 |
| Ecommerce | Hand-picked online stores | 49 |
Each site got one scan of its homepage, between 15 and 18 May 2026. The scanner fetches pages the way a script does, without a browser.
That matters, because a script is exactly what bot protection is built to stop. Of the 2,211 scans, 1,089 came back with response headers the scanner could read. Then we filtered out responses that were a protection screen or an error page instead of the site:
- 127 had a page title such as "Just a moment...", "Attention Required! | Cloudflare", "Access Denied", "403 Forbidden", "Vercel Security Checkpoint" or "429 Too Many Requests"
- 47 carried Cloudflare's challenge-page Content-Security-Policy, which means the headers we measured belonged to the challenge, not the site
- 5 loaded a bot-protection product's scripts instead of the page (one of them also answered from a DataDome server)
Some responses matched more than one rule. In total the filter removed 156, which leaves 933.
One limit we can't remove. 546 of the 933 had no page title to check, because the module that reads titles timed out or failed on them. A protection page with no recognisable title could still hide in that group. To show how much that could matter, the main figures also appear for the 387 responses whose title we could check.
Headline numbers
| What the scan saw | All 933 | The 387 with a checked title |
|---|---|---|
| No Content-Security-Policy header | 742 (80%) | 287 (74%) |
| No Content-Security-Policy that restricts scripts | 855 (92%) | 339 (88%) |
| No Strict-Transport-Security | 557 (60%) | 201 (52%) |
| No X-Frame-Options | 564 (60%) | |
| No X-Content-Type-Options | 569 (61%) | |
| No Referrer-Policy | 690 (74%) | |
| No Permissions-Policy | 861 (92%) | |
| X-Powered-By names the framework | 137 (15%) | 70 (18%) |
| Sets a cookie in the very first response | 338 (36%) | 154 (40%) |
The checked-title group does a little better on the CSP and HSTS rows. Part of that is who is in it: long-tail domains make up 79 percent of the responses without a title but 64 percent of those with one. The order of the problems stays the same in both.
Sending a CSP is not the same as having one
191 of the 933 sent a Content-Security-Policy. What they put in it:
| What the policy did | Sites |
|---|---|
| No script-src or default-src, so no rule for scripts at all | 113 |
| Rules for scripts, but 'unsafe-inline' without a nonce or hash | 55 |
| A nonce or hash, plus 'unsafe-eval' or a scheme source like https: | 8 |
| None of 'unsafe-inline', 'unsafe-eval', *, https:, http: or data: | 15 |

So 113 of the 191 policies say nothing about scripts. Most of those exist for frame-ancestors or upgrade-insecure-requests. Fifteen sites out of 933 had a script policy with none of the loosening keywords. Count the 8 that rely on a nonce or hash and 23 would block an injected inline script. If you want to write one, the CSP generator starts from that strict setting.
Cookies on the first response
338 sites set a cookie before any page had rendered. Among those 338, at least one cookie lacked Secure on 185, lacked HttpOnly on 217 and lacked SameSite on 202. Not every cookie needs HttpOnly, since a language setting read by JavaScript is fine without it. A session cookie without Secure is not.
Third-party scripts without integrity hashes
Of 894 homepages whose HTML the scanner could parse, 337 loaded at least one external script with no Subresource Integrity hash. If that third-party host is compromised, the browser runs whatever it now serves.
Structured data
448 homepages were read by the SEO module, and 299 of them had no JSON-LD in the HTML. That is not a security finding, but the same scan collects it.
By bucket
| Bucket | Responses kept | No CSP that restricts scripts | No HSTS |
|---|---|---|---|
| Long tail | 678 | 643 | 446 |
| Mid | 82 | 75 | 49 |
| Top global | 63 | 45 | 18 |
| Norwegian | 43 | 39 | 24 |
| SaaS | 27 | 14 | 1 |
| Ecommerce | 20 | 20 | 6 |
| Education | 20 | 19 | 13 |
The long tail is 678 of the 933 responses, so it drives every total above. That bucket includes parked domains, gambling sites and randomly named domains alongside ordinary small businesses. The hand-picked buckets are small. SaaS companies did best on both columns, and none of the 20 stores had a script-restricting policy. Twenty is too few to say more than that.
Get the Full Report (PDF)
The State of Web Security 2026. Findings from 500 automated scans. Enter your email, confirm, and get the full PDF with benchmarks and remediation guides.
What we left out, and why
The scanner checks more than this page reports. Four of its modules gave results in this batch that we don't trust:
- TLS versions and ciphers. The deep TLS module returned an empty protocol list on every site where it ran (1,081 of 1,081) and flagged missing TLS 1.3 on all of them. That was a bug in how it read results, not a fact about the web.
- HTTP to HTTPS redirects. The redirect check reported "no redirect" for every site it ran on.
- Exposed files and admin paths. Many servers answer 200 with a normal page for any path, so requests for files like
.envor/admin/produced false hits. - JavaScript libraries with known CVEs. The library check found nothing on any site, which is not believable.
The same goes for the A to F grade, which is a weighted sum that includes those modules. None of them appear above.
Check your own site
Every number here comes from checks you can run on your own homepage in the free scanner. The CSP, cookie and SRI rows are the quickest to act on.
Run Free ScanClaude AI helped me with phrasing and proofreading in this article.
Roy Morken
I build ismycodesafe.com, the scanner behind the numbers on this page. It runs external checks against one URL, nearly all of them read-only, and you can repeat them on your own site. I'm an indie security practitioner based in Norway. Questions about the data or the method: help@ismycodesafe.com.