Table of Contents
Provenance: privacy:browser_extensions
Working log behind Measuring Browser Extensions. Corpus-wide caveats — the venue scope, the selection funnel, the extraction's own error rates — are on corpus and are not repeated here. This page carries only what is specific to that one page: the population rule, every query with its denominator, the report script and its unedited output, the quote checks, the external sources verified and rejected, the reviewer log, and the things that could not be established.
Written as a working log, not as prose. Read it if you are checking a number.
The run
| Date | 2026-09-02 |
| Corpus | data/extract/run1/extractions.jsonl, 5,859 papers, 7 venues (CCS, IMC, NDSS, PoPETs, USENIX Security, TheWebConf, IEEE S&P), 2010–2026 |
| Page created | new; no earlier version to diff against |
| Scripts committed | scripts/ext_fold.mjs, scripts/report_browser_extensions.mjs, scripts/verify_extension_figures.mjs, scripts/ext_quotecheck.mjs, scripts/external_checks_browser_extensions.sh, scripts/build_ext_codeblock.py, scripts/build_provenance_browser_extensions.py, scripts/append_bib_browser_extensions.py, scripts/bib_additions_browser_extensions.bib |
| Measurement scripts | sandbox/cws_sitemap_count.sh, sandbox/cws_sitemap_sample.sh, sandbox/war_dynamic_url.py, sandbox/amo_data_collection.py |
| Published code | pages/ext_corpus.py — embedded on the page as a <file> block |
| Bibliography | 32 entries appended to bibliography; the page cites 49 distinct keys, 32 of them new and 17 already live |
The written boundary
Fixed before the first figure was computed, because “papers about browser extensions” is a phrase and not a population. It is the comment at the top of scripts/ext_fold.mjs and is reproduced here verbatim so the page can be audited without repository access:
IN SCOPE (object/object-partial): the paper produces a reported finding ABOUT browser extensions — their code, their store listings, their permissions, their observable effect on a page, the set a user has installed, or the people who write and use them.
OUT OF SCOPE: a paper that only SHIPS an extension as its instrument or as the deployment vehicle for its own defence (instrument); a paper that assumes a malicious extension in a threat model without measuring any real ones (attack-vector); a paper that draws samples of something else out of an extension store (corpus-source); a citation (mention); and a different sense of the word (homograph).
Candidate sweep
A paper is a candidate if any of four signals fires. Each candidate then carries a hand verdict; report_browser_extensions.mjs exits 1 if a candidate has no verdict or a verdict has no candidate, in both directions.
| Signal | Definition | Candidates |
|---|---|---|
| D | paper.cols.txt matches the object regex ≥ 5 times | 197 |
| S | population[].sourceList names an extension distribution channel | 52 |
| C | classification[].resourceName names extensions | 13 |
| X | a detection[] tuple names extensions | 39 |
| union | 218 |
The object regex, counted rather than tested:
/\bbrowser[- ]extensions?\b|\bChrome extensions?\b|\bFirefox (add-?ons?|extensions?)\b |\bWebExtensions?\b|\bChrome Web Store\b|\baddons\.mozilla\.org\b|\bextension stores?\b |\.crx\b|\bcontent scripts?\b|web[- ]accessible resources?/gi
Why the threshold is 5, and what it costs
The threshold is not defended by roundness. Three measurements bound it:
- A bare
/browser extensions?/iover the corpus fires on 535 papers. Almost all are one citation of Ghostery or uBlock Origin. - The density distribution over the 626 papers with at least one match (report section A3):
| Matches | Papers | Cumulative from the top |
|---|---|---|
| 1 | 248 | 626 |
| 2 | 82 | 378 |
| 3–4 | 99 | 296 |
| 5–9 | 93 | 197 ← the cut |
| 10–19 | 52 | 104 |
| 20–49 | 30 | 52 |
| 50–99 | 16 | 22 |
| 100+ | 6 | 6 |
The cut admits 197 papers on the D signal and leaves 429 out.
- The recall check. Re-running the candidate sweep with a much wider signal — full text matching any extension artefact string (
Chrome Web Store,.crx,moz-extension,chrome-extension://,manifest.json,MV3,web accessible resources,addons.mozilla.org) — adds 32 papers outside the 218. All 32 were read on 2026-09-02. Every one is a reference-list URL, a one-sentence citation, or a different sense of the word. In-scope papers added: 0.
Two of the 32 are worth recording because they are the near-misses: Mistrust Plugins You Must (USENIX Security 2022) is about WordPress plugins and cites the malicious-extension literature in its first paragraph; The Curious Case of the PDF Converter that Likes Mozart (PoPETs 2016) samples from the Google Drive apps section of the Chrome Web Store, which is a store crawl of something that is not an extension. Both are homograph.
Role tally
| Role | Papers | Share of 218 | In scope |
|---|---|---|---|
instrument | 92 | 42.2% | no |
object | 47 | 21.6% | yes |
mention | 38 | 17.4% | no |
object-partial | 21 | 9.6% | yes |
homograph | 13 | 6.0% | no |
attack-vector | 5 | 2.3% | no |
corpus-source | 2 | 0.9% | no |
| 68 in scope |
How the verdicts were made, and the ones a reasonable person would decide otherwise
Every verdict was made by reading the paper's own first-person sentences about extensions, printed by a helper over paper.cols.txt (the query is in the report's –quotes path; the raw dossier is out/ext/firstperson.txt, not published because it is 98 KB of quotations). The distinction that did the most work is between a paper whose results include a statement about extensions and one where extensions appear only in the evaluation of the paper's own system.
| Paper | Verdict | Why, and the case against |
|---|---|---|
| Cookieless Monster, IEEE S&P 2013 | object-partial | It tests user-agent-spoofing extensions and reports that all of them fail to hide the browser — a finding about extensions. Against: the paper is about fingerprinting scripts, and extensions are one section |
| Tales of Favicons and Caches, NDSS 2021 | object-partial | “We also explore the effect of popular privacy-enhancing browser extensions and find that while they can impact performance they do not prevent our attack.” That is a reported finding about extensions. Against: they are a robustness check on an attack |
| Fashion Faux Pas, IEEE S&P 2023 | object-partial | Same shape: six anti-fingerprinting extensions evaluated. Against: they are baselines |
| Spook.js, IEEE S&P 2022 | object-partial | “we look at the security implications of consolidating Chrome extensions”, demonstrated against LastPass. Against: the paper is a transient-execution attack |
| Finding and Preventing Bugs in JavaScript Bindings, IEEE S&P 2017 | object-partial | The Chrome extension system is one of four runtimes checked and 65 errors are flagged in it. Against: the object is the binding layer, not extensions |
| A Security and Usability Analysis of Local Attacks Against FIDO2, NDSS 2024 | attack-vector | It builds malicious extensions and attacks ten servers with them; it measures no real extension. A reasonable person would call this in scope |
| Passwords and FIDO2 Are Meant To Be Secret, CCS 2025 | attack-vector | Same: a Firefox defence evaluated against extensions the authors wrote |
| When Ads Become Profiles, TheWebConf 2026 | attack-vector | Names “browser extensions that abuse legitimate privileges” as its threat model and measures none |
| Automated WebAssembly Function Purpose Identification, TheWebConf 2023 | corpus-source | Crawls 17,682 Chrome extensions and 16,385 Firefox add-ons — for the .wasm files inside them |
| An Empirical Study of Real-World WebAssembly Binaries, TheWebConf 2021 | corpus-source | Same shape, 2,500 Firefox add-ons |
| Analyzing Societal Awareness … Fingerprinting Countermeasures, PoPETs 2026 | mention | Extensions are one of several named countermeasure categories in a survey about fingerprinting; no per-category result is reported. Against: the survey does ask about them |
| Support Personas, PoPETs 2024 | instrument | Builds an extension prototype and studies the interface, not the extension ecosystem |
The single-label choice is a limitation. object-partial is not a confidence level, it is a scope statement, and eleven papers sit close to the line. The page's headline (68) is reported with its split (47 + 21) everywhere so a reader who disagrees can take the 47.
Every query, with its denominator
| Figure on the page | Population | Denominator | Where |
|---|---|---|---|
| 218 candidates | all papers | 5,859 | report §A |
| 68 in scope, 47 + 21 | candidates | 218 | report §A |
92 instrument | candidates | 218 | report §A |
| 535 bare-mention control | all papers | 5,859 | report §A2 |
| 32 added by the widened sweep, 0 in scope | all papers minus the 218 | 5,859 | report §A2 |
| USENIX 24 / 35.3%, IEEE S&P 12, TheWebConf 12, CCS 8, NDSS 6, PoPETs 5, IMC 1 | in-scope papers | 68 | report §B |
| 9 / 14 / 19 / 15 / 11 per period | in-scope papers | 68 | report §B |
| the eight question rows | in-scope papers | 68 | report §C |
| 74 extension-corpus tuples across 38 papers; 50 from a Chrome store | in-scope papers with a unit == “browser-extensions” population tuple carrying a stated n | 68 papers / 74 tuples | report §D |
| snapshot stated: 51.4% of tuples, 55.3% of papers | those tuples / those papers | 74 / 38 | report §D |
| the per-paper store-size table | the same tuples | — | report §D |
| 4 papers record an LLM tool or LLM classification method | in-scope papers | 68 | report §G |
| every per-paper measured figure | that paper's own text | its own | report §H, verify_extension_figures.mjs |
The corpus-wide 43.0% baseline for population.listVersion is from data/extract/OVERVIEW.md (Where the field goes quiet), computed over the 5,712 papers that drew a study population — a different population from the 38 here, which is why it is labelled as a baseline and not compared arithmetically.
The report, unedited
node scripts/report_browser_extensions.mjs. The full output is long; the sections the page reads from are reproduced verbatim below. Nothing here is retyped.
- report_browser_extensions-output.txt
============================================================================== A. THE POPULATION ============================================================================== corpus 5859 papers, CCS, IEEE-SP, IMC, NDSS, PETS, USENIX, WWW, 2010-2026 candidate sweep (D>=5 | S | C | X) 218 papers hand verdicts 218 (sweep and map agree in both directions) Role Papers Share of 218 In scope -------------- ------ ------------ -------- instrument 92 42.2% no object 47 21.6% yes mention 38 17.4% no object-partial 21 9.6% yes homograph 13 6.0% no attack-vector 5 2.3% no corpus-source 2 0.9% no IN SCOPE (object + object-partial) 68 papers = 47 object + 21 object-partial as a share of the whole corpus 1.2% of 5859 OUT OF SCOPE 150 papers of which role=instrument 92 - the extension is the paper's own tool or defence vehicle -- why each candidate fired (a paper can fire on several) -- Signal Candidates ----------------------------------------------------- ---------- D full text matches the object regex >= 5 times 197 S population[].sourceList names an extension channel 52 C classification[].resourceName names extensions 13 X a detection[] tuple names extensions 39 ============================================================================== A2. RECALL CHECK — widening the sweep to any extension artefact ============================================================================== Papers outside the candidate set whose full text names Chrome Web Store, .crx, moz-extension, chrome-extension://, manifest.json, MV3 or a web-accessible resource: 32. All 32 were read (2026-09-02); every one is a citation, a reference-list URL or a different sense of the word. In-scope papers added by the widening: 0. Bare-mention control: /browser extensions?/i alone fires on 535 papers. ============================================================================== A3. THE DENSITY DISTRIBUTION THE THRESHOLD IS CUT FROM ============================================================================== papers whose full text matches the object regex at least once: 626 Matches Papers Cumulative from the top ------- ------ ----------------------- 1-1 248 626 2-2 82 378 3-4 99 296 5-9 93 197 10-19 52 104 20-49 30 52 50-99 16 22 100-+ 6 6 The threshold is 5. Everything at 5 or above is a candidate; the 429 papers below it are not, and A2 is the check on that cut. ============================================================================== B. SHAPE OF THE IN-SCOPE POPULATION ============================================================================== Venue In-scope papers Share of 68 Corpus papers Share of corpus ------- --------------- ----------- ------------- --------------- USENIX 24 35.3% 1410 24.1% IEEE-SP 12 17.6% 767 13.1% WWW 12 17.6% 843 14.4% CCS 8 11.8% 990 16.9% NDSS 6 8.8% 701 12.0% PETS 5 7.4% 510 8.7% IMC 1 1.5% 638 10.9% The base-rate column is the point: a venue share is only interesting against the venue's share of the corpus as a whole. Years In-scope Corpus Share of corpus ---------- -------- ------ --------------- 2010–2013 9 511 1.8% 2014–2017 14 769 1.8% 2018–2021 19 1439 1.3% 2022–2024 15 1955 0.8% 2025–2026* 11 1185 0.9% (* 2025-2026 is provisional: CCS and IMC 2026 have not been held and IEEE S&P / TheWebConf 2026 are incompletely selected. See literature:corpus.) -- per year, in-scope only -- Year In-scope papers ---- --------------- 2010 3 2011 1 2012 3 2013 2 2014 2 2015 5 2016 1 2017 6 2018 4 2019 6 2020 5 2021 4 2022 4 2023 5 2024 6 2025 9 2026 2 ============================================================================== C. WHICH QUESTION EACH IN-SCOPE PAPER ASKS ============================================================================== Question Papers Share of 68 What it asks ------------------ ------ ----------- ------------------------------------------------------------------------ security 18 26.5% Is the extension itself vulnerable, and what does that give an attacker? fingerprintability 11 16.2% Can a page tell which extensions you have installed? blocking-efficacy 11 16.2% Does the protective extension actually protect? privacy-leak 8 11.8% What does the extension send, and to whom? malice 8 11.8% Is the extension deliberately abusive, and can a store catch it? people 7 10.3% What do the users and the developers of extensions know and do? permissions 4 5.9% Does the extension ask for more than it needs? crawl-effect 1 1.5% What does an installed extension do to your own measurement? -- question by period (papers) -- Question 2010–2013 2014–2017 2018–2021 2022–2024 2025–2026* ------------------ --------- --------- --------- --------- ---------- fingerprintability 0 2 5 2 2 security 5 4 4 3 2 privacy-leak 0 1 1 4 2 malice 0 5 2 1 0 blocking-efficacy 1 0 5 2 3 people 0 1 1 3 2 permissions 3 0 1 0 0 crawl-effect 0 1 0 0 0 ============================================================================== D. HOW BIG IS THE STORE? — every extension-corpus size in the in-scope papers ============================================================================== Population tuples with unit == "browser-extensions" and a stated n: 74 across 38 of the 68 in-scope papers of which the source is a Chrome store: 50 tuples -- Every Chrome-store extension corpus in the in-scope papers with n >= 5000 -- (the rule is the size alone; the paper's own sampling word is a column, not a filter, so nothing is silently excluded) Year Venue Extensions Sampling as the paper states it Snapshot stated ---- ------- ---------- ------------------------------- --------------------------------------------- 2012 WWW 5,943 exhaustive not-stated 2014 USENIX 47,940 not-stated not-stated 2015 IEEE-SP 1,000,000 exhaustive 2011-03 to 2014-10 2015 WWW 18,030 exhaustive March 2014 2017 WWW 12,132 exhaustive July 2016 2017 USENIX 10,620 top-n not-stated 2017 WWW 10,000 top-n not-stated 2017 IEEE-SP 10,000 top-n not-stated 2018 CCS 178,893 exhaustive crawled between September 2016 and March 2018 2019 IEEE-SP 66,401 exhaustive not-stated 2019 NDSS 62,994 exhaustive 2018-02 2019 USENIX 59,255 exhaustive November 2017 2019 WWW 58,034 exhaustive October 2017 2020 CCS 152,341 exhaustive January 2014–April 2020 2020 NDSS 102,482 exhaustive not-stated 2021 USENIX 501,349 exhaustive mid 2014 to mid 2019 2021 USENIX 116,485 exhaustive April 2019 2022 CCS 186,434 exhaustive June 2020 2022 CCS 180,361 exhaustive January 2022 2022 CCS 174,355 exhaustive February 2021 2022 USENIX 9,446 not-stated May–June 2021 2023 IEEE-SP 134,196 exhaustive 2022-02-21 2023 IEEE-SP 47,207 purposive 2022-02-21 2024 WWW 160,000 not-stated not-stated 2024 CCS 156,997 exhaustive available as of January 3rd, 2024 2024 USENIX 113,099 exhaustive August 2023 2024 USENIX 39,592 pre-existing-dataset 2023 of those 27 rows, by sampling word: exhaustive=19, not-stated=3, top-n=3, purposive=1, pre-existing-dataset=1 -- every extension-corpus tuple (any store, any size) -- Year Venue n Source Sampling Snapshot ---- ------- --------- ------------------------------------------ -------------------- ---------------------------------- 2010 USENIX 1,827 Mozilla add-ons web site random October 2008 2010 USENIX 699 Mozilla add-ons web site top-n November 2009 2010 USENIX 100 official Chrome extensions gallery top-n not-stated 2010 USENIX 40 addons.mozilla.org top-n not-stated 2011 IEEE-SP 1,139 popular Chrome extensions purposive not-stated 2012 WWW 5,943 Chrome Web Store exhaustive not-stated 2012 USENIX 50 official Chrome extension directory top-n June 2011 2012 USENIX 50 official Chrome extension directory random June 2011 2012 USENIX 50 top 50 Google Chrome extensions top-n not-stated 2012 USENIX 42 top 50 Google Chrome extensions requiring top-n not-stated 2012 USENIX 20 top 20 Google Chrome extensions top-n not-stated 2013 CCS 30 Top 30 Chrome extensions top-n not-stated 2014 USENIX 47,940 Chrome Web Store not-stated not-stated 2014 USENIX 392 Anubis pre-existing-dataset not-stated 2015 IEEE-SP 1,000,000 crawling the web; Safe Browsing; Chrome We exhaustive 2011-03 to 2014-10 2015 WWW 18,030 Google Chrome Web Store exhaustive March 2014 2015 WWW 78 Extension Defender pre-existing-dataset March 2014 2015 WWW 17 Firefox extension store purposive not-stated 2015 WWW 11 Google Chrome extension store purposive not-stated 2017 WWW 12,132 Chrome Web Store exhaustive July 2016 2017 USENIX 10,620 Chrome Web Store top-n not-stated 2017 USENIX 10,620 Firefox Add-ons top-n not-stated 2017 WWW 10,000 Google Chrome Web Store top-n not-stated 2017 IEEE-SP 10,000 Google Chrome Store top-n not-stated 2017 IEEE-SP 2,000 Google Chrome Store purposive not-stated 2017 IEEE-SP 1,000 Google Chrome Store random not-stated 2017 IEEE-SP 1,000 Mozilla Firefox extension market top-n not-stated 2017 USENIX 721 Safari Extension Gallery exhaustive not-stated 2018 CCS 178,893 Chrome Web Store exhaustive crawled between September 2016 and 2018 CCS 2,790 Opera browser extensions exhaustive at the time of analysis 2018 USENIX 46 extension store purposive not-stated 2019 IEEE-SP 66,401 Chrome Extensions exhaustive not-stated 2019 NDSS 62,994 Chrome Web Store exhaustive 2018-02 2019 USENIX 59,255 Chrome Store exhaustive November 2017 2019 WWW 58,034 Google Chrome store exhaustive October 2017 2019 IEEE-SP 9,391 Firefox Add-ons exhaustive not-stated 2019 NDSS 8,646 Mozilla add-on store exhaustive 2018-02-23 2019 IEEE-SP 2,523 Opera Add-ons exhaustive not-stated 2019 WWW 1,000 custom seed list purposive not-stated 2020 CCS 152,341 Chrome Web Store exhaustive January 2014–April 2020 2020 NDSS 102,482 Chrome Web Store exhaustive not-stated 2020 CCS 102 Chrome Web Store convenience January 2014–April 2020 2021 USENIX 501,349 Chrome Web Store exhaustive mid 2014 to mid 2019 2021 USENIX 116,485 Chrome Web Store exhaustive April 2019 2021 IEEE-SP 30 Chrome Web Store purposive 2020-07-16 2021 IEEE-SP 15 Chrome Web Store and default browsers purposive 2020-11-13 to 2020-11-18 2022 CCS 186,434 Chrome Web Store exhaustive June 2020 2022 CCS 180,361 Chrome Web Store exhaustive January 2022 2022 CCS 174,355 Chrome Web Store exhaustive February 2021 2022 USENIX 27,342 Carnus dataset by Karami et al. pre-existing-dataset not-stated 2022 CCS 23,363 Firefox extension store exhaustive April 2021 2022 USENIX 9,446 Chrome Web Store not-stated May–June 2021 2022 USENIX 3,311 Dataset of detected extensions from Laperd pre-existing-dataset not-stated 2023 IEEE-SP 134,196 Chrome Web Store exhaustive 2022-02-21 2023 IEEE-SP 47,207 Chrome Web Store purposive 2022-02-21 2023 USENIX 100 Google Chrome Web Store top-n January 2023 2023 USENIX 20 Chrome Web Store top-n as of April 9, 2022 2023 USENIX 20 Firefox Add-ons top-n as of April 9, 2022 2024 WWW 160,000 Chrome Web Store not-stated not-stated 2024 CCS 156,997 Chrome Web Store exhaustive available as of January 3rd, 2024 2024 USENIX 113,099 Chrome Web Store sitemap exhaustive August 2023 2024 CCS 104,484 Carnus pre-existing-dataset not-stated 2024 USENIX 39,592 Chrome Web Store pre-existing-dataset 2023 2024 CCS 26,591 Mozilla Add-ons Store exhaustive available as of January 3rd, 2024 2024 USENIX 1,000 custom evaluation dataset purposive not-stated 2024 USENIX 200 chrome-mal-ids repository top-n 2023 2024 WWW 170 Google Chrome extension samples pre-existing-dataset not-stated 2025 WWW 15 Chrome Web Store purposive not-stated 2025 NDSS 10 custom Chrome extension set purposive not-stated 2025 USENIX 9 Chrome Web Store top-n not-stated 2025 WWW 3 Firefox Add-ons Store purposive not-stated 2026 PETS 100 Torres et al. wallet dataset pre-existing-dataset 2023 exact versions 2026 PETS 100 Chrome Web Store purposive November 2025 2026 PETS 85 Chrome Web Store purposive November 2025 Snapshot date / list version stated: 38 of 74 extension-corpus tuples (51.4%) counted by paper: 21 of 38 papers (55.3%) corpus-wide BASELINE, a DIFFERENT population: population.listVersion stated by 2455 of the 5712 papers that drew any study population = 43.0% This reproduces OVERVIEW.md's row for the same field exactly. It is NOT comparable to the 55.3% above: different population, different unit. ============================================================================== E. WHAT THE IN-SCOPE PAPERS USED ============================================================================== Tool Category In-scope papers Share of 68 ------------------ ---------------------- --------------- ----------- Selenium browser-automation 13 19.1% Chrome browser 12 17.6% Chromium browser 10 14.7% Google Chrome browser 9 13.2% Firefox browser 8 11.8% Python other 6 8.8% Docker infrastructure 6 8.8% VirusTotal classification-service 5 7.4% Mozilla Firefox browser 5 7.4% Puppeteer browser-automation 5 7.4% Esprima program-analysis 4 5.9% mitmproxy proxy-interception 4 5.9% EasyList blocklist 4 5.9% Ghostery other 3 4.4% Selenium WebDriver browser-automation 3 4.4% EasyPrivacy blocklist 3 4.4% XHOUND program-analysis 3 4.4% Xvfb infrastructure 3 4.4% Brave browser 3 4.4% ChatGPT llm 3 4.4% -- classification[].method over the in-scope papers that classify -- denominator: 61 of 68 in-scope papers carry a classification tuple Method Papers Share of 61 ------------------- ------ ----------- manual-labelling 32 52.5% heuristic-rules 29 47.5% static-analysis 13 21.3% third-party-service 11 18.0% curated-database 9 14.8% dynamic-analysis 9 14.8% blocklist 6 9.8% regex-or-signature 4 6.6% supervised-ml 3 4.9% other 2 3.3% unsupervised-ml 2 3.3% llm 1 1.6% graph-analysis 1 1.6% ============================================================================== F. FULL-TEXT PROBES — upper bounds, over the 5,859-paper corpus ============================================================================== Probe Papers in corpus Of which in scope ----------------------------- ---------------- ----------------- Manifest V3 named 19 11 Manifest V2 named 10 9 declarativeNetRequest 11 6 web-accessible resources 27 19 chrome-extension:// URL 13 12 moz-extension:// URL 4 4 use_dynamic_url 2 2 CRXcavator 4 1 chrome-stats / crx4chrome 0 0 Chrome Web Store sitemap 5 5 an extension-store API 1 1 extension enumeration/probing 5 5 LLM used on extensions 552 6 Every figure here is an upper bound: a match is a mention, not a use. ============================================================================== G. THE 2025-2026 SLICE — is anything superseded? ============================================================================== in-scope papers 2025-2026 (provisional venue-years): 11 2025 CCS [blocking-efficacy] Local Frames: Exploiting Inherited Origins to Bypass Content Blockers. 2025 IEEE-SP [security] Security Analysis of Master-Password-Protected Password Management Protocols. 2025 NDSS [fingerprintability] Cascading Spy Sheets: Exploiting the Complexity of Modern CSS for Email and Browser Fi 2025 USENIX [fingerprintability] Double-Edged Shield: On the Fingerprintability of Customized Ad Blockers 2025 USENIX [privacy-leak] Big Help or Big Brother? Auditing Tracking, Profiling, and Personalization in Generati 2025 USENIX [people] "I have no idea how to make it safer": Studying Security and Privacy Mindsets of Brows 2025 WWW [blocking-efficacy] Breaking the Shield: Analyzing and Attacking Canvas Fingerprinting Defenses in the Wil 2025 WWW [people] Broken Access: On the Challenges of Screen Reader Assisted Two-Factor and Passwordless 2025 USENIX [security] Phishing Attacks against Password Manager Browser Extensions 2026 PETS [privacy-leak] The Masks We (Think We) Wear: Privacy Threats of Browser-Extension Wallets in the Web3 2026 PETS [blocking-efficacy] Privacy vs. Profit: The Impact of Google's Manifest Version 3 (MV3) Update on Ad Block in-scope papers whose schema records an LLM tool or an LLM classification method: 4 2024 WWW Experimental Security Analysis of Sensitive Data Access by Browser Extensions. 2025 USENIX "I have no idea how to make it safer": Studying Security and Privacy Mindsets of 2026 PETS The Masks We (Think We) Wear: Privacy Threats of Browser-Extension Wallets in th 2026 PETS Privacy vs. Profit: The Impact of Google's Manifest Version 3 (MV3) Update on Ad ============================================================================== H. MEASURED RESULTS QUOTED ON THE PAGE (detection[].prevalence) ============================================================================== 2017 USENIX Extension Breakdown: Security Analysis of Browsers Extension Resources installed-extension enumeration 100% of 10,620 Chrome and 10,620 Firefox extensions detected. technique: Probed extension identifiers using timing or Firefox exception behavior. 2017 IEEE-SP XHOUND: Quantifying the Fingerprintability of Browser Extensions. browser-extension fingerprintability At least 9.2% on arbitrary domains and more than 16.6% on popular URLs among the top 10,000 Chrome extensions technique: Static patching, honey pages, DOM instrumentation, and DOM comparison 2019 NDSS latex-gloves-protecting-browser-extensions-from-probing-and-revelation WAR probing by web pages 2,572 out of 10,000 domains probed for 45 different extensions technique: Monitored chrome-extension requests across popular pages 2020 NDSS Carnus: Exploring the Privacy Threats of Browser Extension Fingerprint web-accessible-resource extension fingerprinting 25,866 extensions detected technique: Parsed manifests and probed each WAR URL using response status codes 2018 CCS Mystique: Uncovering Information Leakage from Browser Extensions. Privacy-sensitive information leakage 3,868 of 181,683 extensions (2.13%) technique: Hybrid dynamic taint tracking with static data-flow and control-flow analysis 2024 USENIX Arcanum: Detecting and Evaluating the Privacy Risks of Browser Extensi Sensitive-data taint flows 3,028 extensions (2.68%) across 113,099 analyzed extensions technique: Dynamic taint tracking from sources to exfiltration or storage sinks. 2020 CCS You've Changed: Detecting Malicious Browser Extensions through their U malicious browser extensions 143 malicious extensions in 21 clusters technique: Rating anomalies, malicious keywords, and manual code-delta inspection 2019 IEEE-SP EmPoWeb: Empowering Web Applications with Browser Extensions. exploitable extensions 197 extensions technique: Manual code review and exploit testing 2023 IEEE-SP Detection of Inconsistencies in Privacy Practices of Browser Extension Flow-to-Dashboard inconsistencies 1,290 inconsistent flows across 820 extensions technique: Compared extracted data flows with positive and negative Dashboard statements. 2026 PETS Privacy vs. Profit: The Impact of Google's Manifest Version 3 (MV3) Up ad blocking MV3 and MV2 means were 1.42 and 1.46 blocked ads. technique: Subtracted ad-blocker display-ad counts from no-blocker baseline. ============================================================================== Z. EVERY NON-CORPUS NUMBER ON THE PAGE ============================================================================== These come from primary sources outside the extraction and are re-checked by scripts/external_checks_browser_extensions.sh, not by this report. They are listed here so scripts/check_page_numbers.mjs can run whole-page. Chrome Web Store / Firefox AMO live listing counts external_checks (chromewebstore.google.com, addons.mozilla.org) Chrome Manifest V2 end-of-life dates developer.chrome.com/docs/extensions/develop/migrate/mv2-deprecation-timeline Chrome declarativeNetRequest rule limits developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest Firefox moz-extension:// UUID randomisation bugzilla / MDN use_dynamic_url manifest key developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources Extension IDs / update-manifest endpoints clients2.google.com/service/update2/crx CRXcavator status github.com/duo-labs/crxcavator Repository states, tags and last-push dates GitHub API
Folding
No name fold was written, and that is a decision. Everything the page counts is an enum (classification[].method), an integer (population[].n), a date (population[].listVersion), a hand verdict, or a published regex. The one place a fold would have been needed — free-text tool names in §E — is reported as a ranking with a case-and-punctuation skeleton merge only, exactly as OVERVIEW.md says such fields may be reported, and the page does not quote any figure from it.
The residue that a fold would normally print is instead the homograph role: 13 papers where the word means something else. In full: IPv6 extension headers, ARM's Memory Tagging Extension, WordPress plugins, WeChat and app-in-app mini-programs, Deno third-party modules, Google Drive apps in the Chrome Web Store, RapidAPI listings, “manifest file extension”, “malicious file extensions”, “file extensions” used to identify ML model formats, “extension of the Android Middleware”, and two mobile-app-store papers. Each is listed with its reason inline in ROLE in scripts/ext_fold.mjs.
Quotes and per-paper figures
node scripts/verify_extension_figures.mjs –show. 60 of 60 needles located. Every needle is a phrase the page prints, checked against two renderings — paper.cols.txt with whitespace collapsed, and an independent pypdf extraction of paper.pdf — because the two fail on different sentences. On this run all 60 were found in .cols and none needed the PDF route, which is worth recording: the fallback exists and was not exercised, so it is not evidence that it works here.
Needles were deliberately rewritten from bare numbers into verbatim phrases after the first run: the first version had 53 of 58 needles under 20 characters, which is the length at which a match can happen by accident and “0 not located” starts passing for the wrong reason. After the rewrite only two needles are short (“= 1.46 ” and “= 1.42 ”, from a figure caption in the PoPETs 2026 MV3 paper), and both were read in context by hand.
Three needles failed on the first run and were not fabrications; all three were the page paraphrasing where the paper had different wording, and all three were corrected on the page rather than in the checker:
| Paper | Page had | Paper says |
|---|---|---|
| VEX, USENIX Security 2010 | 1,827 | “a random sample of 1827 extensions from the Mozilla add-ons web site” — no thousands separator |
| IBEX, IEEE S&P 2011 | 1139 Google Chrome extensions | “manifests for over 1,139 popular Chrome extensions” |
| Browser Feature Usage, IMC 2016 | 10% of browser features | “(approximately 10%) that are used by websites, but which ad and tracking blockers prevent from executing more than 90% of the time” |
One needle is present in paper.cols.txt only after undoing a column splice: the CCS 2024 sentence about the store's rounded install counts reads “the Store pro|dataset2 . 3,398 extensions … |vides only inaccurate numbers for popular extensions” in the decolumned text, so the needle is the second half of the phrase.
The extraction's own quotes, behind the store-size table
The per-paper figures above are checked against the papers. Separately, the
evidence.quote the extraction attached to each population tuple is checked
against the rendering the extractor read, because the store-size table is built
entirely from those tuples. node scripts/ext_quotecheck.mjs:
| Verdict | Tuples |
|---|---|
| exact | 54 |
| partial (≥60% of 5-word windows present) | 15 |
| below threshold | 5 |
| total extension-corpus tuples with a quote | 74 |
Below threshold is not “unsupported”. All five were read by hand against
paper.cols.txt and all five are present; three are column splices in the
de-columned text and two are model paraphrases of a nearby sentence:
| Tuple | What the paper actually has |
|---|---|
| IBEX 2011, n = 1,139 | “Figure 2 shows manifests for over 1,139 popular Chrome extensions, to the manifest of an extension called…” — a column splice runs the two columns together mid-sentence |
| Ad Injection at Scale 2015, n = 1,000,000 | “we dynamically execute 25 million binaries and 1 million extensions” and “we cast a wide net and dynamically analyzed over 1 million extensions”. The quote's phrasing (“We used WebEval to evaluate all three sources”) is a paraphrase; the figure is the paper's |
| Experimental Security Analysis 2024, n = 170 | “we use the extension samples provided by Google Chrome” — present, split across a column boundary |
| Privilege Separation in HTML5 2012, n = 42 and n = 20 | both quotes paraphrase the paper's Figure 5 discussion and its top-20 bundling result; the paper's own sentence is “19 out of the top 20 extensions exhibited bundling” |
None of these five figures is used on the page as a headline. The 1,000,000 row is on the page, and it is on the page precisely as a caution that it is not a store size.
A trap that did not fire here, and why it might elsewhere
detection[].prevalence is a model summary of a result, not a quotation (see corpus). Every per-paper figure on the page was therefore checked against the paper's own full text, not against the attached evidence.quote. Two figures were dropped in drafting because the prevalence string and the paper disagreed on the denominator:
- Hulk's population tuple records 47,940 Chrome Web Store extensions; its own text says “Our analysis of 48,332 Chrome extensions”. The difference is a second corpus of 392 samples from Anubis. The page uses 48,332, the paper's number.
- The 2015 malvertising paper's tuple says 18,030; its abstract says “over 18,000”. The page uses 18,030, which is in the paper's methodology section, and says “of 18,030” rather than “over 18,000”.
External sources
Everything below was fetched on 2026-09-02 and is re-checkable with bash scripts/external_checks_browser_extensions.sh. That script prints FAILED explicitly per check, so a blocked or rate-limited call cannot read as a pass.
Verified, and used
| Claim on the page | Primary source | What was actually seen |
|---|---|---|
| No Chrome Web Store listing API | developer.chrome.com/docs/webstore/api_index | the documented API publishes and manages the developer's own item; no list or search endpoint |
42 sitemap shards, lastmod 2026-09-01, 356,984 distinct item IDs | chromewebstore.google.com/sitemap + all 42 shards | sandbox/cws_sitemap_count.sh; every <loc> parsed to a 32-character ID, 0 unparsed, 0 duplicates |
| 30 extensions / 8 themes / 2 dead in a 40-item sample | the store's own detail pages | sandbox/cws_sitemap_sample.sh; existence read from <title> |
/detail/<id> is a soft-404 | three fetches | a fabricated ID and uBlock Origin both return HTTP 200 titled exactly “Chrome Web Store”; uBlock Origin Lite returns “uBlock Origin Lite - Chrome Web Store” |
| uBlock Origin gone from the store | the sitemap ID list and the detail page | cjpalhdlnbpafiamejdnhcphjbkeiagm is not among the 356,984 IDs, and its page is a soft-404 |
CRX endpoint works; 204 on a bad prodversion | clients2.google.com/service/update2/crx | prodversion=120.0 → HTTP 204, 0 bytes; prodversion=140.0.7339.80 → HTTP 200, 9,665,461 bytes, magic Cr24 |
| Install counts rounded | two store pages | “16,000,000 users” (AdGuard AdBlocker), “200,000 users” (Consent-O-Matic); no precise numeric field anywhere in either response |
| AMO API: 99,677 extensions, exact daily users | addons.mozilla.org/api/v5 | count: 99677 for type=extension; average_daily_users: 10766677 for uBlock Origin |
data_collection_permissions coverage | the same API, 400 most-installed | 314 empty (78.5%), 63 [“none”] (15.8%), 23 named (5.8%); sandbox/amo_data_collection.py |
| Edge has no bulk listing; Opera has none | Microsoft Learn; addons.opera.com | Edge's REST API covers your own submissions; Opera's robots.txt and sitemap.xml both 404 |
| Manifest V2 timeline, all six milestones | developer.chrome.com/docs/extensions/develop/migrate/mv2-deprecation-timeline | page footer “Last updated 2026-07-08 UTC”; every quoted phrase on the page is verbatim from it |
| Edge has set no MV2 date | learn.microsoft.com ExtensionManifestV2Availability | “More information about and the timeline of the migration hasn't been established.” |
Firefox keeps blocking webRequest | MDN webRequest vs Chrome webRequest | MDN documents webRequestBlocking as an ordinary permission with no MV3 note; Chrome's says “only available to policy installed extensions” |
declarativeNetRequest limits (nine values) | the reference page's Properties table | read from the raw HTML, not from a summary |
| Service-worker lifetime | …/service-workers/lifecycle | “After 30 seconds of inactivity”; “longer than 5 minutes”; “Any global variables you set will be lost” |
use_dynamic_url semantics, Chrome 130 | the manifest reference + the chromium-extensions announcement | “only allow resources to be accessed through a dynamic ID … regenerated when the browser restarts or the extension reloads”; the version comes from the announcement because the reference page carries no version badge |
Firefox moz-extension UUID | MDN web_accessible_resources | “This ID is randomly generated for every browser instance.” |
| Extension ID derivation | Chromium components/crx_file/id_util.cc | “First 16 bytes of SHA256 hashed public key”; ConvertHexadecimalToIDAlphabet maps hex onto a–p “to avoid ever having a completely numeric host” |
| Chrome Web Store 2026 policy | developer.chrome.com/blog/cws-policy-updates-2026 | “strictly necessary to the extension's disclosed single purpose”; “Enforcement … will begin on August 1, 2026.” |
| Cyberhaven, December 2024 | the company's own post, Internet Archive capture 2024-12-27 | the live URL now redirects to a support site; the archived capture carries the quoted sentences |
| Tool and artefact states | GitHub API and direct fetches | see the table on the page; crxcavator.io does not resolve and duo-labs/crxcavator is HTTP 404 |
| “Rob Wu's crxviewer” | GitHub user API | Rob–W → name: Rob Wu |
Rejected
| Source | Why |
|---|---|
backlinko, aboutchromebooks, sitew.com and similar “how many Chrome extensions” listicles | not primary, and they disagree with each other by a factor of two. The page says Google publishes no count instead of picking one |
| Wikipedia's Chrome Web Store article (“about 138,000 extensions”) | its own citation is ChromeStats, a third-party tracker, retrieved 2022-12-28 — a secondary source dated earlier than the year the prose claims |
ntcompatible, mlq.ai, windowsforum and similar, all asserting Edge will drop MV2 “by end of 2026” | contradicted by Microsoft's own policy page, updated June 2026, which says no timeline has been established |
extensionbooster.net, moldstud.com “Chrome Web Store 2026 compliance guides” | SEO content farms; replaced with Google's own policy post |
| Secondary reporting of “35 extensions / 2.6M users” in the Cyberhaven campaign | no primary source found for the aggregate. The page cites only what Cyberhaven itself stated, and says so |
dl.acm.org for the Mystique artefact | HTTP 403 to every non-browser client; the GitHub repository was used instead |
A model's recall of the declarativeNetRequest limits and the MV2 dates | discarded on principle: both changed in 2025–2026, after training. Every value on the page was fetched |
Could not be established
- No authoritative count of Chrome Web Store extensions exists. Google publishes none. The page reports the sitemap's 356,984 items with the unit stated and a 40-item sample of what those items are, and declines to convert it into an extension count with a confidence interval a 40-item sample cannot support.
- Nothing. The Manifest V2 question that looked like a discrepancy was resolved by measurement rather than left open: 17 of the 198 CRXs served are
manifest_version: 2, which two days after the MV2 removal looks like the sitemap lagging the store. Reading the manifests shows it is not — 0 of the 17 are extensions; 9 are themes and 8 are legacy Chrome apps, neither of which the MV2 phase-out touches. The page states this, because a researcher filtering a corpus onmanifest_versionwill otherwise conclude that MV2 extensions survived. - Apple's current position on Manifest V2 in Safari.
developer.apple.comserves client-rendered pages with no fetchable text, and the only Apple primary source found is a 2022 WWDC transcript. The page therefore says only that the standalone Safari extension gallery no longer exists, which is checkable, and makes no claim about Safari's manifest support. - Whether the two CRX 204s in the sample are refusals or throttling. The endpoint's 204 is documented nowhere and is the same response as for an implausible
prodversion. The published script raises on it rather than counting it as “no such extension”; the sweep counts it as its own outcome. chrome-stats.comcontent. HTTP 403 to every automated fetch. It is named on the page as the source behind most third-party counts, which is checkable from Wikipedia's citation, and nothing is quoted from it.
Original measurements on this page
Five numbers on the page are not in any paper and not in any vendor document. Each is a single-day snapshot and the page says so.
| Measurement | Script | Result | Weakness |
|---|---|---|---|
| Chrome Web Store size, from Google's own sitemap | sandbox/cws_sitemap_count.sh | 42 shards, 356,984 distinct item IDs, 0 unparsed URLs, 0 duplicates | items, not extensions; one day |
| What those items are, from the store page | sandbox/cws_sitemap_sample.sh | 40-item deterministic sample: 30 extensions, 8 themes, 2 with no live detail page | n = 40, and the extension/theme split is read from the store page's category breadcrumb, which is weaker evidence than the manifest |
| What those items are, from the manifest | sandbox/war_dynamic_url.py | 200-item sample, 198 CRXs served: 146 extensions, 44 themes, 8 legacy Chrome apps | the better of the two; supersedes the row above for the composition question |
use_dynamic_url adoption | sandbox/war_dynamic_url.py | CRX served: 198 204 refused: 2 not served: 0 unparsed: 0 network errors: 0; manifest_version histogram: {3: 180, 2: 17, None: 1}; item kind, from the manifest: extension=146 theme=44 app=8; of the 146 extensions, declare web_accessible_resources: 46 (31.5%); Manifest V2 items still served by the CRX endpoint: 17 | n = 200 items, of which 146 are extensions and 46 declare web-accessible resources — so the “0 of 46” is over a small denominator. A deterministic every-1784th sample of the sitemap, representative of listed items and not of installs |
AMO data_collection_permissions coverage | sandbox/amo_data_collection.py | 400 most-installed: 78.5% empty, 15.8% [“none”], 5.8% named | most-installed, not random — the sample is biased towards the add-ons most likely to have been updated, so the true coverage across the whole catalogue is probably lower |
The sampling design in the two sitemap samples is every-k-th over a sorted list of IDs, not random, so a re-run on the same sitemap reproduces the same items exactly. The AMO sample is not of that shape: it is the top 400 by installs, a biased frame, labelled as one in its row above. That is deliberate: a random sample would be unreproducible, and the store changes daily anyway.
The published script
pages/ext_corpus.py is embedded on the page as a downloadable <file> block and carries the whole file, not an abridgement; scripts/build_ext_codeblock.py –check fails if the embedded block stops being byte-identical to the committed one. An earlier draft published only the docstring, which is the failure that guard exists to prevent.
It was mutation-tested, not read:
| Mutant | Expected | Observed |
|---|---|---|
item_exists body replaced with return True | self-test fails | SELF-TEST FAILED — the two negative cases fire |
the status == 204 branch in download_crx disabled | self-test fails | SELF-TEST FAILED — “a two-part prodversion should have raised” |
That is the point of the three-case self-test. A one-case test of the form “the extension I know exists is found” passes on the first mutant, which is exactly the shape of a check that verifies nothing (see corpus and the passing wait condition note in the repository's known traps).
Bibliography
32 entries appended to bibliography before the closing </bibtex>, against a fresh ?do=export_raw of the live page rather than the stale workdir copy. Checks run before saving:
- key collisions against the live page: 0
- internal duplicates in the additions: 0
- DOI, normalised-title and URL collisions against the live page: 0 — a key-string check alone would not have caught the same paper already present under a different key
- 17 of the page's keys already existed and were reused rather than re-created — that is the check that matters most, because a second entry for the same paper under a new key breaks nothing visibly and corrupts the bibliography permanently:
franken2018_cookiejar,karami2020_carnus,laperdrix2021_fingerprinting,agarwal2022_helping,agarwal2024_peeking,pantelaios2024_fv8,thomas2015_injection,borgolte2020_performance,bui2023_detection,ukani2025_local,trampert2025_cascading,demir2024_bannertools,torres2023_wallet,vekaria2025_bighelp,wang2026_masks,elhajjchehade2025_double,lukic2026_mv3
PoPETs and USENIX index records carry no authors and no DOI (100% of both venues), so those entries were built from the venue landing pages. scripts/fetch_authors.py returned affiliations glued into the author list for four of them (Berkeley, Santa Barbara, UC Davis, DeustoTech, Eurecom, UNIRC, UCL, UC3M); those were removed by hand. The two USENIX 2010 records added here share a legacy landing URL with no per-paper page, and their authors were read from the paper's own first page. Every URL in the additions file was then fetched: 16 of 16 return HTTP 200, after two USENIX slugs were corrected in review (see the reviewer log).
Reviewer log
Four review passes, all told explicitly that the reviewer's own context may not be
exhaustive and all handed the same frozen snapshot of the page, the report
script and its output, the external-check output, and this log. The freeze is
out/ext/freeze/ in the workdir. Corrections were applied after each pass
returned, not while it was running, so each finding can be attributed to what the
reviewer actually saw.
Rejections are recorded as carefully as fixes: they are the only evidence of whether a reviewer slot is worth its cost.
Pass 3 — external currency (sonnet)
Re-ran scripts/external_checks_browser_extensions.sh independently and fetched
every external claim from its primary source.
| Finding | Disposition |
|---|---|
The AMO extension count moved between the freeze and the review: count went 99,677 → 99,678 in about fifteen minutes. Every other line of the 175-line external-check output was byte-identical | accepted, and it improved the page. The figure is a live counter, not a published statistic. A footnote now says so and gives both readings, because a reader who re-runs the query and gets a different number should be able to tell drift from error |
| “Manifest V2 is gone, and it went last week” is wrong about the calendar: 2026-08-31 is the Monday of the same week as 2026-09-02 | accepted — already corrected to “two days ago” before this pass returned, which is why the reviewer saw the old wording. Recorded anyway: the reviewer was right about the snapshot it was given |
developer.chrome.com/docs/webstore/api_index redirects to …/api | accepted. The footnote now cites the canonical path and notes the redirect |
A secondary blog claims Chrome raised the declarativeNetRequest static-rule ceiling “from 30,000 to roughly 330,000”. The reviewer checked it against Chrome's own reference page and its 2023-11-15 content-filtering post and found no corroboration | recorded, not used. The page publishes only what the Properties table says |
All nine declarativeNetRequest limits, both service-worker figures, use_dynamic_url and its Chrome 130 provenance, the Firefox UUID claim, Firefox's retained webRequestBlocking, Edge's absent MV2 date, the Chromium ID derivation, the Chrome Web Store 2026 policy date and the Cyberhaven quotes: all verbatim-correct against sources fetched during the review | no change needed |
| Every URL on both pages fetched: 27 of 27 as expected, the only non-200s being the two the page itself asserts are dead | no change needed |
Apple's current Safari Manifest V2 position could not be verified — developer.apple.com serves a client-rendered shell with no fetchable text | no change needed; the page makes no claim about Safari's manifest support, only about the gallery, and the omission is disclosed |
A targeted search for a 2026 development the page has missed — a Manifest V4, a new enumeration countermeasure, a change to the declarativeNetRequest ceilings — turned up nothing | recorded. That is the pass's most useful negative result and it is not visible anywhere else |
Pass 1 — figures versus the script (sonnet)
Re-ran both scripts independently and mutation-tested the guards.
| Finding | Disposition |
|---|---|
A script bug in the report itself. The “exhaustive/whole-store samples only” table was selected by a filter that took a row if its sampling word was exhaustive, or if its n exceeded 5,000 and its sampling word was anything other than top-n — so it admitted any large corpus not literally labelled top-n. (The expression itself contains a logical-or and cannot be written in a DokuWiki table cell; it is in the comment above the corrected line in scripts/report_browser_extensions.mjs.) Five rows in a table headed exhaustive only were not-stated, purposive or pre-existing-dataset. The table's header was a false claim about what the code selected. | accepted, and it is the most valuable finding of the four passes. The filter is now the size alone (n ≥ 5,000) and the paper's own sampling word is a column, so nothing can be silently excluded and the header cannot lie. The comment above the line records the old expression and what it let through |
The page's store-size table said “every Chrome-store corpus in the 68” and was not. It silently dropped 9,446, 47,207, 160,000 and 39,592 while keeping 47,940, whose sampling word is the same not-stated as two of the dropped rows. A draft fix that named “three further” excluded corpora still missed the 160,000 row | accepted. The table is now generated mechanically from the report's rule and carries all 27 rows, with a sentence naming the spread of sampling words as the finding rather than hiding it |
| The page's own quote-check tally was stale: it said “54 of 54” against a tool that printed 57/57 | accepted. Now 60 of 60, and the sentence names the rendering |
| Arcanum was cited to the wrong section: §3 is “System Design”; the target-site discussion is in §4.1 and the 2.68% is in §4.2 with Table 4 | accepted — corrected before this pass returned, and the section titles are now checked against the paper's own headings by verify_extension_figures.mjs rather than asserted |
| An apples-to-oranges comparison: “51.4% … is better than the corpus-wide 43.0%” compares a tuple-level rate over 38 papers with a paper-level rate over 5,712 | accepted. The page now calls 43.0% a baseline and says in terms that the difference is not a measured effect. The report prints the same warning beside the figure |
| “Roughly flat for sixteen years” used only the numerator while the corpus quadrupled underneath it | accepted. The page gives both series and says the share shrank |
| The Safari row asserted “since Safari 13” with no check in the external script | accepted. The claim is dropped, Apple's own distribution sentence is quoted, and a Safari check is now check 24 in the external script |
| The reviewer could not reproduce the frozen outputs byte-for-byte, because both scripts had been edited after the freeze while it worked | recorded as a process failure, not a page defect. It is the reason the freeze exists and the reason it has to be a real freeze. The reviewer flagged it rather than assuming, which is the behaviour the brief asked for; four of its eight findings had in fact already been fixed in the unfrozen copy, and it said so each time |
Verified clean: the 218/68/47/21 splits and every percentage and sum, the year buckets closed at both ends, the <file> block byte-identical to the committed script, ext_corpus.py –self-test passing, and — by mutation-testing both directions — that the report really does exit 1 when a verdict has no candidate or a candidate has no verdict | no change needed |
Pass 2 — citations, quotes and attribution (sonnet)
Checked every citekey, every new BibTeX entry against the venue's own page or the paper's first page, every quoted sentence against the paper, and every external footnote against its source.
| Finding | Disposition |
|---|---|
A fabricated middle name in a BibTeX entry. snyder2016_browser listed “Taylor, Cynthia Bagier”. The paper's own first page, Crossref and the author's own pages all say Cynthia Taylor; “Bagier” appears nowhere | accepted. The entry is corrected. The name came from bibgen.mjs, which reads OpenAlex — so publisher metadata is not a defence: a generated entry needs the same check as a hand-written one. This is the finding that most justifies the pass |
Two dead URLs in the additions: usenixsecurity23/presentation/nisenoff-defining and usenixsecurity25/presentation/agarwal-mindsets both 404. The real slugs are nisenoff-broken and agarwal-shubham | accepted. Both corrected, and every one of the 16 URLs in the additions file was then fetched: 16 of 16 return 200 |
| The provenance's “11 reused citekeys” list named six keys the page never cited | accepted, and it exposed a real gap rather than a bookkeeping slip. Those six — agarwal2022_helping, borgolte2020_performance, ukani2025_local, demir2024_bannertools, torres2023_wallet, vekaria2025_bighelp — are all in-scope papers the page should have been citing. All six are now cited, one of them in a new section on how the eleven “does the protective extension protect?” papers operationalise “protect”. The count is now 49 citekeys, 17 reused, 32 new |
verify_extension_figures.mjs carried needles for four papers the page did not cite, inflating the needle count without checking anything on the page | accepted in effect, resolved the other way: rather than deleting the needles, the page now cites all four papers, so every needle checks something the page prints. Worth recording that the reviewer's proposed fix and the applied fix are opposite and both close the finding |
| “Three USENIX 2010 records” — there are two in the additions; the third was already live | accepted, corrected |
Five duplicate entry pairs already in bibliography — the same paper under two keys (lerner2016internet/lerner2016_internet and four others). None is cited by this page | recorded, not fixed. Out of scope for this page and a page-rewriting job, not a bibliography job. Filed as the dedupe-bibliography work item, with the note that a key-string check does not find these and the dedupe has to be by DOI and normalised title |
The Cyberhaven archived post could not be re-fetched — archive.org returned HTTP 429 throughout the review | no change; the capture was fetched successfully during the run and again during the currency pass, and the footnote names the capture date so a reader can retry |
| Verified clean: all citekeys resolve, no DOI/title/URL collisions between the additions and the live page, all 32 author lists correct apart from the one above, all 60 needles genuinely present in their papers, and every external footnote verbatim against its primary source | no change needed |
Pass 4 — generic, no checklist (fable)
It returned after the pages were first published; its findings were applied in a follow-up save. Twelve findings, of which four were already fixed by the self-audit below (Edge/Opera, “Nobody does”, “Nobody has published it”, and two placeholder slots that were filled between the freeze it saw and publication) — it said so where it could tell. The rest:
| Finding | Disposition |
|---|---|
| A novelty claim contradicted by the page's own report. The page said Torres et al. “turned the question around and measured the web… rather than only in a lab”; report §H records [1Sjösten, Alexander; Van Acker, Steven; Picazo-Sanchez, Pablo; Sabelfeld, Andrei (2019): "Latex Gloves: Protecting Browser Extensions from Probing and Revelation Attacks", in: Proceedings of the Network and Distributed System Security Symposium. (Link)] doing exactly that in 2019, “2,572 out of those 10,000 domains probe for WARs” | accepted. The sentence now credits the 2019 precedent and says what Torres's contribution actually is: the object, not the framing |
| The methodology claimed more quote coverage than the guard gives. “Every per-paper figure quoted above was checked” — but several figures on the page (akhawe's 5%-of-functions, dong's 23-of-top-30, lukic's 21%-vs-0%) have no needle | accepted. The sentence now says the check covers the 64 needles and not every number on the page, and points at where the rest come from |
| “Every result older than those is a result about Manifest V2” over-reaches, and the page contradicts it three sections earlier by describing VEX and Djeric attacking Firefox's XPCOM model | accepted. Scoped to Chrome, with the pre-MV2 model and the Firefox/Opera corpora named |
| The detection table's “Introduced” column credits the wrong paper: the page's own pitfalls section says WAR probing was introduced at CODASPY 2017, outside the corpus | accepted. The column is now headed Introduced, in this corpus |
| “They agree to within half a percentage point” — 2.68 − 2.13 = 0.55 | accepted, and the difference is now stated as a number |
| The opening box's 146 + 44 + 8 sums to 198, not 200, and the two refusals are explained 400 lines later | accepted. The box says “(198 served; the endpoint declined 2)” |
| This log contradicted itself three ways: “Four numbers” over a five-row table; “all three samples are every-k-th” when the AMO sample is a top-400; and “byte-identical apart from the docstring, which is all the page shows” when the page shows the whole script | all three accepted. The last is the serious one — it is the exact “published code must be the real script” failure, described in the log as though it had happened. The whole file is on the page and build_ext_codeblock.py –check proves it |
The external-check script has vacuous checks: check 1 prints its “expected” comment and no fetched evidence; check 9 probes an obsolete constant name and prints NOT FOUND rather than FAILED; the MDN webRequestBlocking quote in a page footnote is fetched by no check | accepted as correct, not fixed in this sitting. It is the trap this log lectures about, found in this log's own script. Recorded here and carried by the ext-generic-review work item |
Carnus row labels three things and gives two numbers; the “all but one from 2021 onwards” people claim has no guard; the log names out/ext/freeze/ when this pass saw freeze2 | accepted, not fixed — recorded and carried by the same work item |
| “The page answers its own question well… the What-to-Report box is the best section”, structure sound, all re-checked arithmetic correct, the published script reads correctly as code and as prose, and its self-test genuinely asserts negative cases | recorded |
The lesson this pass repeats. Three of its findings — the Torres novelty claim, the Manifest V2 over-reach, and the WAR-probing attribution — are each true in the sentence where they appear and false against a different section of the same page. That is the third run on this site where the generic pass earned its slot by reading the joins that no focused brief owns.
What no reviewer caught
Three errors survived all of the focused passes and were caught by re-reading the page against the corpus afterwards. They are the same shape, and the shape is worth naming: an absolute negative that no figure and no citation contradicts. A figures pass checks that every number traces to the report; a citation pass checks that every claim attached to a key is supported by that key's paper. Neither can see a sentence that says nobody, because there is no figure and no citation to check it against.
| What the page said | What is true | How it was caught |
|---|---|---|
| “whether the vector is closed is a measurement, not a documentation question. Nobody has published it.” | [2Agarwal, Shubham; Fass, Aurore; Stock, Ben (2024): "Peeking through the window: Fingerprinting Browser Extensions through Page-Visible Execution Traces and Interactions", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security. (DOI)] published exactly that measurement: “we only observe 109 fingerprintable extensions using this option”. The page's own measurement is a second, later one over a different population — which is a better claim than the one it replaced | by running the corpus probe for use_dynamic_url and reading the two hits instead of counting them. The probe was already in the report; only its two contexts had not been read |
| “Nothing in the corpus measures Edge or Opera add-ons” | Opera was measured twice — 2,790 extensions [3Chen, Quan; Kapravelos, Alexandros (2018): "Mystique: Uncovering Information Leakage from Browser Extensions", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security. (DOI)] and 2,523 [4Somé, Dolière Francis (2019): "EmPoWeb: Empowering Web Applications with Browser Extensions", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)] — both as a side-corpus to a Chrome study, and not since 2019 | by listing every non-Chrome sourceList in the in-scope population, which took one query and had not been run because no figure on the page needed it |
| “Report the extension set… Nobody does.” | Unknowable from this corpus: the extraction schema has no field for the extension set of a crawl profile. The page now says that, which is the honest version and also the more useful one | by asking what query would support the sentence, and finding there is none |
The general rule this run ends with: before a page ships, grep it for nobody, nothing, never, no one, the only and at all, and for each one name the query that supports it or scope the word. Every one of the three above would have been caught by that grep. None of them was caught by three reviewers.
That grep was then run over the whole page and produced seventeen hits. Nine were left alone because they are explicitly corpus-scoped and the report supports them (“the only paper in this corpus written from inside the store”; “nothing since asks whether extensions request more permission than they use”). Eight were rewritten, and one of those eight was a second real error of the same kind: “Edge … is currently the only mainstream store where the old platform is still live” — Firefox is the other, which the same page says two sections earlier. That is the “two sections meet” failure exactly, and it survived a figures pass, a citation pass and a currency pass because neither half of it is wrong on its own.
TODOs this page leaves open
- The
use_dynamic_urlsample is 200 items. A store-wide figure is one crawl away and would settle whether extension enumeration is a live threat or a historical one. - The 40-item store-composition sample supports “roughly three-quarters extensions” and nothing narrower.
- Nobody has re-measured what an installed extension does to a crawl since IMC 2016. That is the gap this page most wants filled.
- The
object/object-partialline is single-label and eleven papers sit close to it; a second reader would move some.
See also
- corpus — the dataset-wide provenance page: venue scope, selection funnel, extraction error rates
- browser_protection and requests — the two nearest neighbours, and the reason this page's boundary is drawn where it is
References
- [1]
- Sjösten, Alexander; Van Acker, Steven; Picazo-Sanchez, Pablo; Sabelfeld, Andrei (2019): "Latex Gloves: Protecting Browser Extensions from Probing and Revelation Attacks", in: Proceedings of the Network and Distributed System Security Symposium. (Link)
- [2]
- Agarwal, Shubham; Fass, Aurore; Stock, Ben (2024): "Peeking through the window: Fingerprinting Browser Extensions through Page-Visible Execution Traces and Interactions", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security. (DOI)
- [3]
- Chen, Quan; Kapravelos, Alexandros (2018): "Mystique: Uncovering Information Leakage from Browser Extensions", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security. (DOI)
- [4]
- Somé, Dolière Francis (2019): "EmPoWeb: Empowering Web Applications with Browser Extensions", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)
