User Tools

Site Tools


provenance:privacy:browser_extensions

This is an old revision of the document!


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?/i over 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 by hand on 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 — true by construction, not a
measurement: the verdict map is keyed on candidates, so a non-candidate
cannot carry a verdict. The hand reading is what rules them out.
 
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%)
  of those, carrying an actual year:    37 of 74 (50.0%)
  stated but with NO year in the value: 1
     2018 CCS n=2790 :: "at the time of analysis"
  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.
 
==============================================================================
H2. THE PEOPLE HALF — the guard for "all but one are from 2021 onwards"
==============================================================================
  2017 CCS      Let's Go in for a Closer Look: Observing Passwords in Their Natural Habitat.
  2021 IEEE-SP  They Would do Better if They Worked Together: The Case of Interaction Problems Betwe
  2022 PETS     How Can and Would People Protect From Online Tracking?
  2023 USENIX   Defining "Broken": User Experiences and Remediation Tactics When Ad-Blocking or Trac
  2024 PETS     Block Cookies, Not Websites: Analysing Mental Models and Usability of the Privacy-Pr
  2025 USENIX   "I have no idea how to make it safer": Studying Security and Privacy Mindsets of Bro
  2025 WWW      Broken Access: On the Challenges of Screen Reader Assisted Two-Factor and Passwordle
 
  people papers: 7; from 2021 onwards: 6; before 2021: 1
 
==============================================================================
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. 66 of 66 needles located as of 2026-09-221). Every needle is a phrase from the paper, 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 66 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. How much of the page the 66 actually cover is now measured, not asserted. The script prints it: 40 of the 66 guard a figure the page prints, 9 guard a figure it does not, and 17 carry no number distinctive enough to test either way — and it lists all 26 of the latter two groups so they can be read. Until 2026-09-22 this section said every needle is a phrase the page prints, which was an assertion and was false: a needle is the paper's sentence, and the page usually states the figure in its own words. A needle in the 9 still does real work — it proves the figure exists in the paper — it just is not evidence about this page. Quote the 40, not the 66, when you mean page coverage.

After the rewrite three needles are short: “= 1.46 ” and “= 1.42 ” from a figure caption in the PoPETs 2026 MV3 paper, and “2,523” — the Opera corpus of [1Somé, Dolière Francis (2019): "EmPoWeb: Empowering Web Applications with Browser Extensions", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)], added when the self-audit corrected the nothing measures Opera claim. All three were read in context by hand. The script prints the count, so the figure in this sentence is checkable against it.

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
rescued from the PDF 4
below threshold in both renderings 1
total extension-corpus tuples with a quote 74

Re-run 2026-09-21 with the PDF fallback. The old figure was 5 below threshold; 4 of the 5 reach threshold against an independent pypdf rendering of the same paper.pdf and are reported as rescued. exact (54) and partial (15) did not move. See Quote-check refresh, 2026-09-21 at the foot of this page.

The one still below threshold in both renderings is the IBEX 2011 n = 1,139 tuple, at 56% coverage — the first row of the table below, and a column splice. By elimination the other four are the remaining rows: Ad Injection at Scale 2015, Experimental Security Analysis 2024 and both Privilege Separation in HTML5 2012 tuples.

Two of the four rescued are the two the table calls paraphrases, and that is a caution about what rescued means. It means ≥60% of the quote's five-word windows are present in the second rendering — not that the extraction is verbatim. A paraphrase that keeps most of the paper's wording can clear the threshold in a cleaner rendering. The hand verdicts below are the stronger evidence and they are unchanged.

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 converts it with the 200-item CRX sample (146 extensions of 198 served, 73.7%) to “on the order of 260,000 extensions”, saying in the same sentence that a 200-item sample can only bound that loosely. The earlier 40-item sample is superseded for the composition question and supports nothing narrower than roughly three-quarters extensions. Until 2026-09-22 this bullet said the page declined to convert at all, and cited the 40-item sample for it — a description of a decision the page had already stopped making.
  • 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 on manifest_version will otherwise conclude that MV2 extensions survived.
  • Apple's current position on Manifest V2 in Safari. developer.apple.com serves 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.com content. 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

Five review passes, all told explicitly that the reviewer's own context may not be exhaustive and all handed a frozen snapshot of the page, the report script and its output, the external-check output, and this log. Corrections were applied after each pass returned, not while it was running, so each finding can be attributed to what the reviewer actually saw.

There is more than one freeze, and saying so matters, because a finding is only attributable if you know which text produced it. The three focused passes saw out/ext/freeze/; the generic pass of 2026-09-02 saw out/ext/freeze2/, the re-frozen copy taken after those passes' fixes were applied; the generic pass of 2026-09-22 saw out/ext/freeze3/, taken after the deferred findings below were closed. Until 2026-09-22 this paragraph said the same freeze and named only the first — which the 2026-09-02 pass flagged about itself, and which stood uncorrected for three weeks.

freeze3 was not a clean freeze either: the external-check re-run overwrote external.txt inside it while pass 5 was reading it, and pass 5 noticed and said so. Nothing in its findings depends on that file's live values, but it is the second time this page has made the same mistake, so it is recorded here rather than quietly fixed.

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 [2Sjö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, and closed on 2026-09-22 (see Deferred findings, closed below). Originally deferred with this note: 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, and all three closed on 2026-09-22 — see Deferred findings, closed below. They were recorded here and carried by an ext-generic-review work item that, it turned out, was never actually filed: the only record they existed was this row
“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.

Pass 5 — generic, no checklist (fable), 2026-09-22

Run over out/ext/freeze3/ — the page, the provenance, the three scripts and their fresh outputs — after the deferred findings below were closed, so that the newest and least-reviewed material was the material under review. Twelve findings confirmed, five raised as suspected. It opened with a process note that is itself a finding: external.txt inside the frozen directory changed while it was reading it, because the external-check re-run overwrote it. That is pass 1's “the freeze was not a freeze” failure, committed again, by me.

Finding Disposition
A fingerprintability paper was illustrating the eleven blocking-efficacy papers. The Does the Protective Extension Protect? section says “Eleven of the 68 papers ask this” and then closes with “[3Nguyen, Hoang Dai; Vadrevu, Phani (2025): "Breaking the Shield: Analyzing and Attacking Canvas Fingerprinting Defenses in the Wild", in: Proceedings of the ACM Web Conference. (DOI)] and [4El Hajj Chehade, Saiid; Stock, Ben; Troncoso, Carmela (2025): "Double-Edged Shield: On the Fingerprintability of Customized Ad Blockers", in: Proceedings of the USENIX Security Symposium. (Link)], above”. The report tags [4El Hajj Chehade, Saiid; Stock, Ben; Troncoso, Carmela (2025): "Double-Edged Shield: On the Fingerprintability of Customized Ad Blockers", in: Proceedings of the USENIX Security Symposium. (Link)] fingerprintability, and the page's own detection table treats it as a fingerprinting paper — “fingerprints the filter list rather than the blocker” accepted, and it is the best finding of the pass. The bullet now keeps [3Nguyen, Hoang Dai; Vadrevu, Phani (2025): "Breaking the Shield: Analyzing and Attacking Canvas Fingerprinting Defenses in the Wild", in: Proceedings of the ACM Web Conference. (DOI)], says in terms that [4El Hajj Chehade, Saiid; Stock, Ben; Troncoso, Carmela (2025): "Double-Edged Shield: On the Fingerprintability of Customized Ad Blockers", in: Proceedings of the USENIX Security Symposium. (Link)] is not one of the eleven, and gives the reason. This is the two-sections-meet failure again: both sentences are right where they sit
The needle fix left the stale number on the public page. The count moved to 66 and the provenance was corrected; the content page still said “64 of 64 located” and “a check on those 64” accepted, fixed. Mine, from earlier the same day, and exactly the defect the residue table does not fix the prose rule exists for: I corrected the section that computes the number and not the sentence that quotes it
Every needle is a phrase the page prints was false. At least six needles guard figures that appear nowhere on the page: 699, 29,428, 854, 18,937, 190 extensions, 5.5% accepted, and resolved by measuring instead of asserting. verify_extension_figures.mjs now computes page coverage and prints the residue: 40 of the 66 guard a figure the page prints, 9 guard one it does not, 17 carry no number distinctive enough to test. The prose gives all three and says to quote the 40 when you mean page coverage. A needle in the 9 still proves its figure exists in the paper — it is just not evidence about this page
The new failure mechanism covers 3 of 26 checks, and the closing line claimed all of them. fail()/expect() are called in checks 1, 9 and 26 only. Five checks use || echo FAILED, which prints the word without incrementing FAILS. The remaining eighteen are regex printers that emit nothing on a 403, a 429 or a reworded source. Yet the run ended “all checks produced fetched evidence” accepted in full, and it is the sharpest thing said about my own work today. Closing the vacuous-check finding made the summary line claim more than before the fix. The header now sets out which checks are asserted, which are reported and which are unasserted, and the closing line says the 3 asserted checks passed; the other 23 are printers — an empty section is not a pass. Converting the other 23 is the ext-external-assertions work item, filed this time
The report printed a hand verdict as though the run computed it. “All ${extra.length} were read (2026-09-02)” — the count is computed, the reading and the date are string literals. If the corpus moved, the report would claim 40 papers were read on a day 32 were. Same shape at the 429 papers below it accepted, fixed, and mutation-tested. The hand-read set is pinned at 32; a different count now prints HAND-READ SET IS STALE and exits non-zero (verified by setting it to 33). The 429 is computed from the distribution. The In-scope papers added: 0 line now says it is true by construction — the verdict map is keyed on candidates, so a non-candidate cannot carry a verdict — rather than posing as a measurement
The provenance contradicted the page on the store composition. Could not be established said the page “declines to convert [the sitemap count] into an extension count”, citing the 40-item sample; the page converts, from the 200-item sample, to “on the order of 260,000 extensions”. The provenance's own tools table says the 200-item sample supersedes the 40 accepted, fixed. The bullet describes what the page actually does and its stated caveat; the TODO that rested on the 40-item sample is rewritten
Only 51.4% state a snapshot date at all counted a non-date. The filter excludes only not-stated and null, so the Mystique Opera tuple's “at the time of analysis” passed as a stated date accepted, fixed, and made computable. The report now prints the dated/undated split and the offending value: 37 of 74 (50.0%) carry an actual year, and the one exception is named. The per-paper 21 of 38 is unaffected — the same paper's Chrome tuple gives a real range. A non-sentinel value is not automatically a value
A top-400 sample generalised to the catalogue. “currently a signal about 5.8% of the catalogue”, where the provenance says the sample is most-installed, not random, so true coverage is probably lower accepted, fixed. 5.8% is now stated as an upper bound from the head of the catalogue, not an estimate of it
A bullet contradicted itself two clauses later. “Every whole-store paper rebuilt one” against “Corpora //do get passed between groups”// and two pre-existing-dataset tuples in the report accepted, fixed — either rebuilt one or inherited one privately
A dangling reference. The page promised the provenance says “which one it is still missing”; no pass is missing accepted, fixed — it now promises what each pass changed
The rewritten Carnus row carried its own changelog. “two novel vectors, not three” contrasts with a version the reader has never seen, and sat under a bullet calling Carnus a comparison of four vectors accepted, fixed. The row names the two vectors Carnus introduces, says the other two are the rows above, and drops the not three
The needle ledger does not close. The footnote's 60 → 64 → 66 story cannot accommodate the 2,523 Opera needle, which the next paragraph attributes to the self-audit accepted, and fixed by giving up the reconstruction. The footnote now says the increments cannot be reconstructed from this log and that the count is only trustworthy from the script — which is the honest version and the one that stops the next person quoting a number out of prose
It also flagged five suspected items it could not decide: the people verdict on the CCS 2017 password study (which, if it is instrument rather than people, makes the sentence all seven); the Firefox WAR result of 2017 sitting beside Firefox: closed to this vector with no reconciliation; four quantified claims the report does not print; and none needed the PDF route resting on a run without --show recorded. The last is settled here: re-run with --show, 66 of 66 located in .cols, 0 via the PDF — the claim is true and now has a run behind it. The other four are carried by the ext-suspected-four work item. The CCS 2017 verdict is the one worth doing first: the guard added today formally depends on it, and it has no row in the borderline-verdicts table
Verified clean, by re-derivation: the role table, venue split, question table by row and by every period column, the 27-row sampling-word split, 146+44+8=198, 73.7%, 0.55 pp, the 49 citekeys — and that the H2 guard does what the page says and fails on both halves no change needed

What this pass says about the previous four. Six of its twelve findings are in material written the same day, by me, while closing the previous pass's deferred list: the stale 64, the overstated needle claim, the overstated external-check summary, the Carnus changelog, and two more. A correction is new, unreviewed text. The pass that reviews a fix is worth as much as the pass that found the defect, and this log had not been run that way before today.

Deferred findings, closed 2026-09-22

The generic pass of 2026-09-02 accepted findings it did not have time to fix and recorded them as carried by an ext-generic-review work item. That item was never filed. They survived only because the two rows above recorded them, which is the argument for writing a deferred finding down in the same detail as a fixed one: for three weeks this log was the entire backing store.

They are two rows but six findings, which is itself worth noting — a deferred row that bundles three things is three things that can be lost together. All six reproduced exactly as described, and all six are now closed.

Deferred finding What it was How it is closed
Check 1 of external_checks_browser_extensions.sh was vacuous It grepped the raw HTML for a sentence, so the tag attributes broke its [^.] run and it matched nothing; it then printed its own -- expected: the Web Store API publishes/manages YOUR OWN item comment. The re-run on 2026-09-22 reproduced it: the whole of check 1 was two lines, one of them the comment. An assertion with no fetched evidence under it, in the script whose header promises the opposite The check strips tags before matching, and an expect helper prints the located sentence or records a failure. It now prints Google's own “The Chrome Web Store API lets you programmatically publish and manage your Chrome Web Store items”, and separately probes for a listing endpoint rather than asserting there is none
Check 9 probed an obsolete constant and printed NOT FOUND MAX_NUMBER_OF_DYNAMIC_AND_SESSION_RULES is the pre-Chrome-120 constant and is gone from the reference page. The check printed NOT FOUND as an ordinary output line inside a run that exited 0 The two constants that replaced it, MAX_NUMBER_OF_DYNAMIC_RULES and MAX_NUMBER_OF_SESSION_RULES, are probed instead, plus MAX_GETMATCHEDRULES_CALLS_PER_INTERVAL for the getMatchedRules quota the page publishes. A missing constant now prints FAILED and exits non-zero. The page's figures were right; only the script's name for one of them was stale
The MDN webRequestBlocking quote was fetched by no check The page's footnote at “Firefox supports both, and keeps blocking webRequest” quotes MDN verbatim. Chrome's side of that comparison was check 21; the Firefox side was checked by nothing, so the whole Firefox half of the MV2/MV3 divergence rested on an unverified quote New check 26 fetches the MDN page and locates the sentence. It is there verbatim: “To use the 'blocking' feature, the extension must also have the 'webRequestBlocking' API permission”. The check also reports whether MDN has begun mentioning Manifest V3 on that page, which is the way this claim would go stale
The Carnus row labelled three things and gave two numbers “Intra- and inter-browser messaging, and outgoing HTTP” against “450 and 859 extensions respectively”. Reading the paper makes it a worse error than a missing number: Carnus's inter-communication is the outgoing-HTTP vector — “two novel fingerprinting techniques … namely outgoing HTTP requests and intra-browser message exchanges” — so the row invented a third vector the paper does not have The row names the two vectors, says in terms that they are two and not three, and adds Table I's Unique column (105 and 181) with the paper's own gloss, “unique to each technique (i.e., cannot be detected by any other technique)” — flagged explicitly as not the sense of unique used in the identifiability rows above it. Two needles were added to verify_extension_figures.mjs so both the caption and the two-not-three claim are checked against the paper
The people claim had no guard “Seven of the 68 papers study the humans rather than the code, and all but one are from 2021 onwards.” Nothing computed either half New report section H2 prints the seven papers with their years and asserts both halves. Mutation-tested in both directions: moving the cut-off to 2022 fails and names the two papers, changing the expected count fails. The claim is true — 2017, 2021, 2022, 2023, 2024, 2025, 2025
This log named one freeze when there were two The opening paragraph said all four passes were handed the same frozen snapshot and named out/ext/freeze/, when the generic pass had been handed freeze2. A finding is only attributable to a reviewer if you know which text it saw The paragraph names all three freezes, says which pass saw which, and dates them. This pass's own snapshot is out/ext/freeze3/

And one thing the deferred list did not contain. Closing the Carnus row and the people guard changed the needle count, and that exposed a number this page had been publishing three different ways for the same quantity: “60 of 60” in Quotes and per-paper figures, “the 64 needles” in the Pass 2 row below, and “the 70-needle per-paper check” in the 2026-09-21 quote-check refresh. The check has never been 70. 60 went stale the moment the citations pass added four needles, and nothing pointed at it, because the sentence that has to change is in a different section from the fix that changes it. All three are corrected, the figure is 66, and the sentence now says to re-run the script rather than quote it.

A process failure worth more than any of the findings. The prose file this provenance page is built from, pages/provenance_privacy_browser_extensions.txt, was three weeks stale: the markup sweep of 2026-09-17 and the quote-check refresh of 2026-09-21 were both edited straight onto the live page and never back- ported. Rebuilding with build_provenance_browser_extensions.py would have deleted both sections silently — the builder checks that no slot is empty, but it cannot check for content that only exists downstream of it. The prose file was reconstructed from the live page and the rebuild was then proved byte-identical to what was published before any of today's edits were applied. If you edit one of these pages in the browser, back-port it the same day, or the next build eats it.

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.” [5Agarwal, 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 [6Chen, 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 [1Somé, 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_url sample 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 store-composition figure rests on a 200-item CRX sample (146 of 198 served are extensions). A larger draw would tighten the on the order of 260,000 estimate, which is currently an order-of-magnitude statement and is written as one.
  • 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-partial line is single-label and eleven papers sit close to it; a second reader would move some.

See also

References

[1]
Somé, Dolière Francis (2019): "EmPoWeb: Empowering Web Applications with Browser Extensions", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)
[2]
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)
[3]
Nguyen, Hoang Dai; Vadrevu, Phani (2025): "Breaking the Shield: Analyzing and Attacking Canvas Fingerprinting Defenses in the Wild", in: Proceedings of the ACM Web Conference. (DOI)
[4]
El Hajj Chehade, Saiid; Stock, Ben; Troncoso, Carmela (2025): "Double-Edged Shield: On the Fingerprintability of Customized Ad Blockers", in: Proceedings of the USENIX Security Symposium. (Link)
[5]
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)
[6]
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)

Markup sweep, 2026-09-17

Mechanical rendering repair only: a fresh live raw/XHTML export of 188 pages was checked with check_wrap.mjs and check_typography.mjs. Affected plugin tags, CLI flags and heading markup were repaired; no figures or substantive prose were changed. The resulting source and rendered DOM were re-checked after saving.

Quote-check refresh, 2026-09-21

The 2026-09-04 cols-vs-PDF audit on corpus showed that 73.1% of evidence quotes that cannot be located in paper.cols.txt are present in an independent pypdf rendering of the same paper.pdf. ext_quotecheck.mjs already carried the fallback; the verdict table in The extraction's own quotes was copied from a pre-fallback run. Re-run, unedited:

$ node scripts/ext_quotecheck.mjs
extension-corpus population tuples with a quote: 74
  exact:            54
  partial (>=60% of 5-word windows): 15
  rescued from the PDF: 4
  below threshold in BOTH renderings:  1   <- read these, do not count them as fabrications
    IEEE-SP/2011/verified-security-for-browser-extensions  n=1139  cov=0.56
      We conducted a simple analysis of manifests for over 1,139 popular Chrome extensions
Figure Was Is Why
tuples with a quote 74 74 population unchanged
exact 54 54 unchanged
partial (≥60% of 5-word windows) 15 15 unchanged
rescued from the PDF — 4 these were inside the old 5
below threshold 5 1 (in both renderings) 5 = 4 + 1 exactly

What the refresh does not change. All five were already read by hand and all five are present, so no claim on browser_extensions rested on the 5. What it changes is the figure a reader would quote as this page's quote-failure rate: 1 of 74, not 5 of 74. And it exposes something worth stating — two of the four rescued are the two tuples the hand read calls paraphrases, so rescued is a statement about the rendering, not a warrant that the extraction is verbatim.

Scope of this edit. The verdict table and the paragraph under it. The per-paper needle check (64 needles on that date, not the 70 this sentence originally said), the store-size table, the population figures and every citation stand as published; report_browser_extensions.mjs was not re-run. browser_extensions carries no quote-check figure, so it was not edited.

Item Value
Date 2026-09-21, unsupervised
Command node scripts/ext_quotecheck.mjs
Artifact out/qc0921b/ext.txt
Script changes none
Reviewers one sonnet figures-vs-script pass
Pages saved this page only
1)
The needle set has grown since first publication and this sentence did not follow it. It was written at 60; the citations pass added needles for papers the page began citing; the self-audit added the “2,523” Opera needle; the run of 2026-09-22 added two with the corrected Carnus row. The count reached 64 at some point before 2026-09-21 and is 66 now — but the exact increments cannot be reconstructed from this log, which is the point: the count is only trustworthy from the script. The Quote-check refresh, 2026-09-21 section below said 70-needle, which the check has never been. Re-run the script rather than quoting any figure in prose, including this one.
provenance/privacy/browser_extensions.1790063320.txt.gz · Last modified: by karel.kubicek.claude