# FINAL tables v3 - post fourth review (2026-09-24), de-identified-release edition

Final rubric = rubric3.py + csp3.py v3. This file is generated by reanalysis4.py from the
de-identified scan-2 dataset alone (per-row classes; no header values, no domains),
except the labeled precomputed constants in sections 4, 8 and 10, which were derived
from the private raw data (scan 1 and all raw header values are not released).

## Glossary (standard across all artifacts)

1. Sampled rows (n=7,040): directory rows drawn at random, covering 7,022 unique initial registrable domains.
2. Registrable domain: the domain name with the last two labels, or three when the second-level part is a common public suffix such as co.uk. A heuristic, not a full Public Suffix List lookup.
3. Final registrable domain: the registrable domain of the final URL after redirects. "Final host" means the full hostname, used only for the HSTS host-scope table.
4. Usable responses (n=5,642 rows, 5,614 unique final registrable domains): rows with a usable HTTPS response. Tables label this base "all-usable".
5. HTTP-200 responses (n=4,701 rows): usable rows whose final status was 200.
6. Principal base, also called "dedup-200" (n=4,688): unique final registrable domains among the HTTP-200 responses. One row kept per final registrable domain - the LAST row in scan-2 check-completion order (the released file's row order; sorting by row_id, i.e. scan order, changes the dedup). Every headline figure uses this base. Code and column names such as n_dedup200 refer to this base.

Bases: principal base (dedup-200, n=4,688 unique final registrable domains), HTTP-200 (n=4,701 rows), all-usable = usable responses (n=5,642 rows). Wilson 95% CIs.

## 1. COOP split - full v2 vocabulary, all three bases

| Base | same-origin | allow-popups | noopener-allow-popups | restrict-properties | unsafe-none (no-op) | unknown-token | malformed | missing |
|---|---|---|---|---|---|---|---|---|
| dedup-200 | 35 | 15 | 0 | 0 | 19 | 0 | 4 | 4,615 |
| HTTP-200 | 36 | 18 | 0 | 0 | 20 | 0 | 4 | 4,623 |
| all-usable | 352 | 19 | 0 | 0 | 20 | 0 | 4 | 5,247 |

Effective total (index point) = 50 (1.1%) on dedup-200. The 4 malformed sites sent the space variant 'same-origin allow-popups', which browsers ignore. The dedup-200 allow-popups count (15) includes one policy with a report-to parameter. noopener-allow-popups and restrict-properties are recognized non-default values (both earn the point; restrict-properties carries a browser-support caveat): zero occurrences of either in the data.

## 2. Exact counts, dedup-200 base (n=4,688) - every per-control figure

- HSTS: strict+preload 344 (7.3%), strict 234 (5.0%), base+preload 135 (2.9%), base 675 (14.4%), short 665 (14.2%), missing 2,635 (56.2%). Strict-or-better = 578 (12.3% [11.4-13.3]). Present at all = 2,053 (43.8%).
- CSP (CSP3 v3 classes): no-CSP 3,696 (78.8%); no-script-directive 804 (17.2%); allowlist 173 (3.7%); nonce/hash-strict 5 (0.1%); strict-dynamic+anchor 8 (0.2%); invalid 2. Script-restricting 186 (4.0%). unsafe-inline EFFECTIVE: element channel 172 (3.7%), attribute channel 170 (3.6%). unsafe-eval effective 157 (3.3%); full wildcard effective 81 (1.7%); subdomain-wildcard in effective script directive 55 (1.2%). **Passes the header-only script-CSP rule (index point): 8 (0.17% [0.1-0.3]).** Report-only CSP: 37 (0.8%).
- Clickjacking (frame-ancestors precedence + duplicate normalization): effective 1,463 (31.2% [29.9-32.5]), ineffective 15 (0.3%), missing 3,210 (68.5%). The 15 ineffective: 3 conflicting XFO repeats, 6 obsolete ALLOW-FROM, 5 other values browsers ignore, 1 site whose enforced frame-ancestors is a bare wildcard (precedence). Precomputed breakdown from the raw values; the total is reproducible from this dataset.
- XCTO nosniff: 1,861 (39.7%).
- Referrer-Policy: secure 373 (8.0%), weak 252 (5.4%), invalid 1 (0.02%), missing 4,062 (86.6% - browser default applies).
- Permissions-Policy: restrictive 374 (8.0%), wildcard-only 10 (0.2%), missing 4,304 (91.8%).
- COOP effective: 50 (1.1%).
- Version-token disclosure: leak 960 (20.5%), clean 3,728 (79.5%). Exact rule in section 5.
- **None-of-seven headline (dedup-200): 2,331 = 49.7% [48.3-51.2].**
- Composite: 8/8 = 1 site; 7/8 = 8 sites. Median 1; mean 1.80.

## 3. Score distribution 0-8 under the final rubric

Dedup-200 (n=4,688), count of checks passed:

| Score | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| Sites | 523 | 1,979 | 958 | 745 | 221 | 161 | 92 | 8 | 1 |
| % | 11.2 | 42.2 | 20.4 | 15.9 | 4.7 | 3.4 | 2.0 | 0.2 | 0.02 |

HTTP-200: 523/1983/959/746/222/164/94/9/1 (mean 1.80). All-usable: 538/2366/1018/892/235/172/400/20/1 (mean 2.03). The bar at 8 holds one site: one site passed all 8 checks. Score 0 = all eight including version hygiene; the none-of-seven headline counts zero on the seven protective checks only.

## 4. HSTS final-host scope

A strict HSTS policy observed on a www final host does not cover the registrable apex (the browser never saw an apex response). Of the strict-or-better passes:

| Base | apex host | www subdomain | other subdomain |
|---|---|---|---|
| dedup-200 | 316 (54.7%) | 260 (45.0%) | 2 (0.3%) |
| HTTP-200 | 318 (54.7%) | 260 (44.8%) | 3 (0.5%) |
| all-usable | 337 (55.3%) | 268 (44.0%) | 4 (0.7%) |

So 260 of 578 dedup-200 strict passes (45.0%) come from a www final host: treat the headline HSTS figure as 'the site as reached from the apex URL presents strict HSTS', not 'the apex itself emits HSTS'. Precomputed from the raw values (not in this dataset): two responses carried joined duplicate HSTS fields ('max-age=63072000, max-age=300' style; first max-age wins, matching browsers) and seven sent max-age=0 (removal signal; never strict).

## 5. Version hygiene - exact rule

The rule considers exactly four headers: Server, X-Powered-By, X-AspNet-Version, X-AspNetMvc-Version. A digit anywhere in any of them = disclosure (no point). Dedup-200 facts (reproducible from this dataset's name-only fields): 67 sites send X-AspNet-Version, 37 send X-AspNetMvc-Version; 27 sites' leak is triggered ONLY by the ASP.NET headers (they would pass under a Server/X-Powered-By-only rule); 0 sites pass while sending an ASP.NET version header. Known heuristic limits (documented, not changed): any digit trips it, including dates or digit-bearing product names; a framework banner without digits (e.g. 'ASP.NET') does not.

## 6. Per-state (HTTP-200 base, final rubric, states with n>=150) + omnibus test

| State | n | Mean /8 | Pass none of 7 [95% CI] |
|---|---|---|---|
| New York | 189 | 1.87 | 42.9% [36.0-50.0] |
| Massachusetts | 191 | 1.94 | 46.6% [39.7-53.7] |
| Texas | 333 | 1.86 | 47.1% [41.8-52.5] |
| Ohio | 221 | 1.89 | 48.9% [42.4-55.4] |
| Illinois | 170 | 1.83 | 49.4% [42.0-56.9] |
| Pennsylvania | 204 | 1.67 | 50.5% [43.7-57.3] |
| California | 570 | 1.76 | 50.5% [46.4-54.6] |
| Washington | 205 | 1.69 | 51.2% [44.4-58.0] |
| Florida | 194 | 1.66 | 56.2% [49.2-63.0] |

Omnibus test across the 9 states (2x9 chi-square of none-of-7 vs rest): chi2 = 8.77, df = 8, p = 0.362 - no detectable state-to-state heterogeneity. The widest pair is Florida vs New York: pooled two-proportion z = 2.61, p = 0.0091, Newcombe 95% interval for FL - NY = 3.3 to 23.0 pp (difference 13.3 pp). The unadjusted pairwise p does not survive a Bonferroni threshold of ~0.00139 for 36 pairs, and the omnibus is null, so the state section stays descriptive: 'State estimates varied descriptively. We did not prespecify or power the study for state comparisons, and we did not conduct multiplicity-adjusted state tests, so we do not rank states or infer state-level differences.' Per-state counts for all 53 states/territories are in data/state-counts-2026-09-24.tsv.

## 7. None-of-seven and clickjacking, all three bases, final rubric

- Dedup-200: none-of-7 2,331/4,688 = **49.7% [48.3-51.2]**. Clickjacking effective 1,463 = 31.2% [29.9-32.5].
- HTTP-200: none-of-7 2,335/4,701 = 49.7% [48.2-51.1]. Clickjacking effective 1,472 = 31.3% [30.0-32.7].
- All-usable: none-of-7 2,733/5,642 = **48.4% [47.1-49.7]**. Clickjacking effective 1,955 = 34.7% [33.4-35.9].

## 8. Retention and reproducibility

What this release contains: the de-identified scan-2 dataset (per-row final-rubric classes, platform label, dedup group, host kind; no header values, no domains, no cookies, no nonces, no timestamps), the parser source (csp3.py v3, rubric3.py), the test suites (test_csp3.py, test_golden.py), this analysis script, the precomputed state counts, the sampler (seed 42) and scanner source. Every table in this file except the labeled constants is regenerated from that dataset by the one command in the README.

Raw-pipeline retention facts (precomputed on the private data, reported here because the raw values are not released): scan 2 captured the COMPLETE final-response header block per site; the only cap was a whole-block cap of 65,536 bytes applied at capture time, before analysis-time classification; the largest observed block was 15,362 bytes (row r4370) - 23% of the cap - so no scan-2 record was truncated; the largest single values were CSP 13,852 chars, Set-Cookie 5,820, Permissions-Policy 969, X-Frame-Options 131, HSTS 91, Referrer-Policy 64, COOP 50; two records genuinely lacked a Content-Type (tiny blocks). Scan 1 kept only per-check values truncated at 400 characters at scan time AFTER in-memory classification (values at exactly 400 chars: CSP 438, clickjacking 6, Permissions-Policy 9 on the all-usable base; 121 / 6 / 8 on the HTTP-200 base). Only final-response headers were captured; redirect-hop headers were discarded. Nonce redaction is classification-lossless (locked by golden tests: every qualifying and rare policy classifies identically with nonces redacted).

De-identification: row_id is the sample row number in scan order (r0001-r7040); dedup_group is a keyed pseudonym of the final registrable domain (key not released); no site is named anywhere in this release. Honest caveat: anyone who re-runs the sampler with seed 42 against the same Curlie snapshot can re-derive the sample and thereby re-identify rows - that is inherent to reproducible sampling and is the decided release shape.

## 9. CSP3 class tables, all three bases

### HTTP-200 base (n=4,701)

| Class | n | % of base |
|---|---|---|
| No CSP at all | 3,702 | 78.7% |
| CSP present, no script-restricting directive | 806 | 17.1% |
| Allowlist-based | 174 | 3.7% |
| Nonce/hash strict | 9 | 0.2% |
| strict-dynamic + anchor | 8 | 0.2% |
| Invalid/unparseable | 2 | 0.04% |
| **Script-restricting total** | **191** | **4.1%** |
| of which: unsafe-inline EFFECTIVE (element channel) | 173 | 3.7% |
| of which: unsafe-inline EFFECTIVE (attribute channel) | 171 | 3.6% |
| of which: unsafe-inline present-but-IGNORED | 5 | 0.1% |
| of which: unsafe-eval EFFECTIVE | 162 | 3.4% |
| of which: full wildcard (bare */scheme) EFFECTIVE | 82 | 1.7% |
| of which: subdomain-wildcard in effective script directive | 58 | 1.2% |
| **Passes the header-only script-CSP rule (index point)** | **8** | **0.17% [0.1-0.3]** |

### all-usable base (n=5,642)

| Class | n | % of base |
|---|---|---|
| No CSP at all | 4,301 | 76.2% |
| CSP present, no script-restricting directive | 829 | 14.7% |
| Allowlist-based | 177 | 3.1% |
| Nonce/hash strict | 325 | 5.8% |
| strict-dynamic + anchor | 8 | 0.1% |
| Invalid/unparseable | 2 | 0.04% |
| **Script-restricting total** | **510** | **9.0%** |
| of which: unsafe-inline EFFECTIVE (element channel) | 176 | 3.1% |
| of which: unsafe-inline EFFECTIVE (attribute channel) | 174 | 3.1% |
| of which: unsafe-inline present-but-IGNORED | 5 | 0.1% |
| of which: unsafe-eval EFFECTIVE | 481 | 8.5% |
| of which: full wildcard (bare */scheme) EFFECTIVE | 84 | 1.5% |
| of which: subdomain-wildcard in effective script directive | 58 | 1.0% |
| **Passes the header-only script-CSP rule (index point)** | **8** | **0.14% [0.1-0.3]** |

WARNING for the rewrite: the all-usable base's 325 nonce/hash-strict policies are mostly CDN bot-challenge interstitials (Cloudflare challenge pages carry nonce CSPs, and 316 of the 318 script-src-attr uses on this base sit on those Cloudflare 403 responses). On real 200 pages that class is 9 sites. Never quote the all-usable CSP class mix without this caveat.

### dedup-200 base (n=4,688)

| Class | n | % of base |
|---|---|---|
| No CSP at all | 3,696 | 78.8% |
| CSP present, no script-restricting directive | 804 | 17.2% |
| Allowlist-based | 173 | 3.7% |
| Nonce/hash strict | 5 | 0.1% |
| strict-dynamic + anchor | 8 | 0.2% |
| Invalid/unparseable | 2 | 0.04% |
| **Script-restricting total** | **186** | **4.0%** |
| of which: unsafe-inline EFFECTIVE (element channel) | 172 | 3.7% |
| of which: unsafe-inline EFFECTIVE (attribute channel) | 170 | 3.6% |
| of which: unsafe-inline present-but-IGNORED | 4 | 0.1% |
| of which: unsafe-eval EFFECTIVE | 157 | 3.3% |
| of which: full wildcard (bare */scheme) EFFECTIVE | 81 | 1.7% |
| of which: subdomain-wildcard in effective script directive | 55 | 1.2% |
| **Passes the header-only script-CSP rule (index point)** | **8** | **0.17% [0.1-0.3]** |

### Manual audit of the 8 qualifying policies (de-identified: pseudonyms q1-q8, no row IDs; nonces redacted)

- q1 - strict-dynamic + real nonce anchor; no script-src-attr, attribute channel inherits the nonce-anchored script-src. Genuinely clean under the header-only rule. (Also the one site that passed all 8 checks.)
- q2 - nonce + strict-dynamic, tight single-page policy; no script-src-attr. Clean under the rule.
- q3 - script-src nonce + strict-dynamic; the junk (*, data:, unsafe-eval) sits in default-src and never reaches scripts; no script-src-attr. Clean under the rule.
- q4, q5 - Canva platform policies: nonce + strict-dynamic, wasm-unsafe-eval only; no script-src-attr. Clean under the rule (platform-issued, not site-owner work).
- q6 - script-src 'none': ships no scripts at all; handlers blocked by the same fallback. Clean under the rule.
- q7 - 15 sha256 hashes + host allowlist; no script-src-attr. Clean under the rule, but retains subdomain-wildcard hosts (*.google.com etc.) as valid script sources.
- q8 - two nonces + long host allowlist with subdomain wildcards; no script-src-attr. Same caveat as q7.

None of the 8 ships script-src-attr. Header syntax alone does not establish nonce freshness, markup matching, or allowlist bypassability.

### Platform and sector disposition of the 8 qualifiers (HTTP-200 base)

- Platform labels: Cloudflare-edge 3, nginx 2, Apache 1, Microsoft IIS 1, no listed label 1. Shopify/Wix/Squarespace/GoDaddy 0.
- Sector: Industrial 3, General 2, Legal Services 1, Computers & Internet 1, Animals 1.

## 10. Drift scan1 vs scan2 - precomputed (scan 1 not released)

Scan 1 did not preserve raw response headers (graded in-memory; only per-check values truncated at 400 chars survive), and scan 1 is not part of this release. These figures were computed on the private data with the final rubric on both sides: for the 4,484 of 4,608 both-200 rows whose scan-1 check values are complete (124 excluded for 400-char truncation), 7 rows changed at least one index item = 0.16% [0.08-0.32]. Breakdown of changed items: clickjacking 2, Permissions-Policy 3, XCTO 3, version hygiene 2 (rows r0792, r1939, r2472, r2962, r6215, r6279, r6820). **The earlier 13/4,608 = 0.28% figure was an old-rubric diagnostic; six of those 13 were XFO-duplicate artifacts that both scans now grade the same way. This supports, but does not prove, stability: the 124 excluded rows are exactly those with the longest CSPs.**

## 11. Golden test corpus

test_golden.py covers the review's full audit list: multiple header fields and comma joining (incl. values that must not be naively combined); duplicate CSP directives first-wins; multiple enforced policies (cumulative, intersection semantics); script-src-elem/script-src-attr fallback; 'unsafe-inline' with nonces/hashes/'strict-dynamic'; 'unsafe-hashes'; scheme sources and wildcard host forms; empty/malformed/duplicated/mixed-case directives; the full 8-value Referrer-Policy vocabulary with list processing; XFO duplicates, ALLOW-FROM, frame-ancestors precedence; HSTS max-age=0, duplicate fields, boundaries, final-host scope; Permissions-Policy defaults and unknown directives; every recognized COOP value; and the version-token rule's edges. Real-policy fixtures are limited to the eight qualifying CSPs, de-identified (nonces redacted, query strings stripped, site-identifying hosts replaced by neutral placeholders; every fixture classifies identically to the original, locked by the golden tests) and real values that cannot identify a site (e.g. 'sameorigin, sameorigin', 'same-origin allow-popups', 'max-age=0'); odd values that contain domains are represented by synthetic equivalents.

## 12. Disposition (reproducible from this dataset)

Sampled rows: 7,040. Usable HTTPS responses: 5,642. Failures: Could not connect over HTTPS: SSLCertVerificationError 381, Redirected to a non-HTTPS address 215, Request timed out 204, Could not connect over HTTPS: SSLEOFError 199, Domain does not resolve 192, Could not connect over HTTPS: SSLError 97, Could not connect over HTTPS: OSError 58, Too many redirects 29, DNS lookup failed 13, Domain resolves to a non-public network address 4, Redirected to an invalid address 4, Could not connect over HTTPS: RuntimeError 2.
Status breakdown (usable): 200 4701, 403 577, 202 245, 404 59, 500 11, 307 9, 429 8, 401 5, 503 4, 405 4, 520 3, 526 3, 400 3, 406 2, 521 2, 502 1, 525 1, 410 1, 423 1, 523 1, 530 1.
Unique final registrable domains: usable 5,614; HTTP-200 4,688. Final destinations serving more than one sampled row, among usable responses: 15 groups covering 43 responses.

## 13. Platform and sector tables (HTTP-200 base, exploratory)

Platform labels (identified n=3,481 = 74.0%; rules and precedence in the data dictionary):

| Label | n | Mean /8 | None of 7 [CI] | HSTS strict | CSP script-restricting | CSP qualifies | Clickjacking | nosniff |
|---|---|---|---|---|---|---|---|---|
| Cloudflare-edge | 1357 | 1.72 | 59.6% [57.0-62.2] | 8.5% | 3.5% | 0.2% | 18.5% | 32.6% |
| Apache | 898 | 1.35 | 71.0% [68.0-73.9] | 10.1% | 2.0% | 0.1% | 19.6% | 20.5% |
| nginx | 731 | 1.80 | 49.8% [46.2-53.4] | 8.2% | 4.9% | 0.3% | 38.9% | 36.5% |
| Shopify | 168 | 3.01 | 0.0% [0.0-2.2] | 0.0% | 0.0% | 0.0% | 100.0% | 100.0% |
| Microsoft IIS | 104 | 0.58 | 72.1% [62.8-79.8] | 10.6% | 7.7% | 1.0% | 24.0% | 14.4% |
| GoDaddy builder | 86 | 2.00 | 0.0% [0.0-4.3] | 100.0% | 0.0% | 0.0% | 100.0% | 0.0% |
| OpenResty | 57 | 1.77 | 35.1% [24.0-48.1] | 7.0% | 1.8% | 0.0% | 56.1% | 63.2% |
| Flywheel (managed WP) | 55 | 1.16 | 0.0% [0.0-6.5] | 0.0% | 0.0% | 0.0% | 3.6% | 100.0% |
| Amazon S3 | 16 | 0.88 | 75.0% [50.5-89.8] | 18.8% | 6.2% | 0.0% | 25.0% | 25.0% |
| Wild Apricot | 6 | 2.00 | 0.0% [0.0-39.0] | 0.0% | 100.0% | 0.0% | 0.0% | 100.0% |
| Pagely (managed WP) | 3 | 0.00 | 100.0% [43.9-100.0] | 0.0% | 0.0% | 0.0% | 0.0% | 0.0% |

Sector (sectors with n>=30):

| Sector | n | Mean /8 | None of 7 [CI] | Clickjacking [CI] | Recognized COOP [CI] |
|---|---|---|---|---|---|
| General | 1620 | 1.82 | 48.9% [46.5-51.3] | 32.5% [30.3-34.9] | 0.9% [0.6-1.5] |
| Real Estate | 541 | 1.49 | 56.2% [52.0-60.3] | 22.6% [19.2-26.3] | 0.9% [0.4-2.1] |
| Restaurants and Bars | 408 | 2.07 | 46.1% [41.3-50.9] | 31.1% [26.8-35.8] | 4.4% [2.8-6.9] |
| Shopping | 372 | 2.11 | 35.5% [30.8-40.5] | 48.1% [43.1-53.2] | 0.3% [0.0-1.5] |
| Construction and Maintenance | 368 | 1.67 | 51.6% [46.5-56.7] | 25.3% [21.1-30.0] | 0.3% [0.0-1.5] |
| Computers and Internet | 226 | 1.81 | 58.0% [51.4-64.2] | 30.5% [24.9-36.8] | 0.9% [0.2-3.2] |
| Legal Services | 194 | 1.69 | 59.3% [52.2-65.9] | 27.3% [21.5-34.0] | 1.0% [0.3-3.7] |
| Automotive | 175 | 1.73 | 54.3% [46.9-61.5] | 36.0% [29.3-43.3] | 1.1% [0.3-4.1] |
| Industrial | 169 | 1.72 | 50.3% [42.8-57.7] | 32.5% [25.9-39.9] | 0.6% [0.1-3.3] |
| Home and Garden | 79 | 1.59 | 53.2% [42.3-63.8] | 20.3% [12.9-30.4] | 1.3% [0.2-6.8] |
| Animals | 74 | 1.95 | 50.0% [38.9-61.1] | 28.4% [19.4-39.5] | 0.0% [0.0-4.9] |
| Organizations | 49 | 1.73 | 53.1% [39.4-66.3] | 26.5% [16.2-40.3] | 0.0% [0.0-7.3] |
| Event Planning | 47 | 1.66 | 46.8% [33.3-60.8] | 19.1% [10.4-32.5] | 0.0% [0.0-7.6] |
| Advertising and Marketing | 47 | 1.81 | 55.3% [41.2-68.6] | 27.7% [16.9-41.8] | 4.3% [1.2-14.2] |
| Employment | 39 | 1.79 | 61.5% [45.9-75.1] | 33.3% [20.6-49.0] | 2.6% [0.5-13.2] |

