Table of Contents
Provenance: privacy:javascript
Working notes behind javascript — every query, its population and its denominator, the report script and its unedited output, the folds and their residue, the quotes that were checked, and what could not be established. Corpus-level caveats that apply to every page on this site are on corpus and are not restated here.
Partly reconstructed. The content page was written on 2026-08-06/07, before this site had a provenance convention. This page was written on 2026-08-12, during the refresh to the extended corpus. Sections marked recorded were produced by the 2026-08-12 run. Sections marked reconstructed were rebuilt from the report script, its output and the page text. The page's Methods, and Which Ones Are Current table, the tool maintenance-status table and the two 2025 crawl-design results were researched and verified outside the corpus by the original run and were not re-verified here.
1. What this page is backing
| Item | Value |
|---|---|
| Content page | javascript |
| Report script | scripts/report_javascript.mjs (–wiki for DokuWiki tables, –list for the full paper list) |
| Population rule and folds | scripts/js_fold.mjs |
| Quote verification | scripts/quote_check.mjs –classification javascript |
| Data | data/extract/run1/extractions.jsonl, 5,859 papers, 7 venues, 2010–2026 |
| Refreshed | 2026-08-12 |
2. The population, which is this page's hardest problem
Reconstructed (rule), recorded (counts). Neither obvious schema handle finds this literature, so membership is built from three independent signals and a paper joins if it measures the web platform and matches at least one:
- a
detection[]tuple whose phenomenon — not merely itstechnique— names a script, JavaScript, WebAssembly,eval, SRI or a browser-API surface; - a
classification[]tuple whosetargetnames a script; - the paper used or produced a JavaScript-specific analysis tool, from an ordered family list.
Requiring only the technique would admit every paper that used a line of JavaScript to run an experiment. Three tool families appear in the tool table but are deliberately not membership signals, because their non-analysis use was measured rather than assumed: OpenWPM (drags in an IPv6-scanning study, a QUIC website-fingerprinting paper and an HSTS study using it as a plain crawler), Emscripten (papers that compile to WebAssembly), SpiderMonkey (RIDL, where the engine is the victim). Three further papers — Spectre, Fallout, RIDL — are removed by hand with the reason recorded inline in js_fold.mjs.
| Population | Old (4,322 corpus) | New (5,859 corpus) |
|---|---|---|
| JS-analysis papers | 160 | 206 |
| …with ≥1 classification tuple | 153 | 198 |
| …that ran a crawl | 128 (80.0%) | 165 (80.1%) |
| …that recorded a crawl configuration | 126 | 163 |
| comparison column: all papers with a crawl configuration | 829 | 1,080 |
Signal combinations, which is how to see whether the rule is load-bearing:
| Signal combination | Old | New |
|---|---|---|
| classification only | 43 (26.9%) | 57 (27.7%) |
| detection only | 42 (26.3%) | 53 (25.7%) |
| detection + classification | 23 (14.4%) | 30 (14.6%) |
| tool only | 21 (13.1%) | 26 (12.6%) |
| tool + detection + classification | 12 (7.5%) | 19 (9.2%) |
| tool + detection | 11 (6.9%) | 13 (6.3%) |
| tool + classification | 8 (5.0%) | 8 (3.9%) |
The distribution is essentially unchanged, which is the useful thing to know: the population rule scaled with the corpus rather than drifting. Roughly a quarter of the population is admitted by each single signal, so dropping any one of the three would lose a quarter of the field.
3. Running it
cd /workspace/artifacts/wiki node scripts/report_javascript.mjs # every figure, both fold residues node scripts/report_javascript.mjs --wiki node scripts/report_javascript.mjs --list # the full 206-paper list node scripts/quote_check.mjs --classification javascript --show 13 node scripts/check_page_numbers.mjs \ pages/privacy_javascript.txt out/new/report_javascript.txt \ '===== What This Literature Actually Is =====' '===== Open Questions ====='
check_page_numbers.mjs left 22 figures unaccounted. All 22 are non-corpus figures and none was changed by the refresh: F1 scores and feature counts quoted from AdFlush, Zafar et al.'s 20.6% and 92.8%, Lauinger et al.'s 87.7% / 46.5% / 37.8% / 9.7%, the 77,423-domain denominator, arXiv identifiers, tool version numbers and commit dates, and 4,322 quoted as the old corpus size. This page has an unusually high count because roughly half of it is a guide to methods rather than a corpus report.
4. What the refresh changed
Recorded.
| Figure | Old | New |
|---|---|---|
| Population | 160 | 206 |
program-analysis tool users | 959 → 215 web (22.4%) | 1,385 → 299 web (21.6%) |
code-or-binary-analysis | 1,063 → 249 (23.4%) | 1,484 → 347 (23.4%) |
| LLVM / Soot / IDA Pro / FlowDroid | 66 / 61 / 36 / 34 | 101 / 81 / 62 / 48 |
| Esprima, top JS parser in the corpus | 15 | 23 |
| Per 1,000, by period | 23.5 / 45.0 / 41.3 / 33.9 | 27.4 / 44.2 / 42.4 / 34.8 / 24.5* |
| Tracking/advertising classification | 25 (15.6%) | 29 (14.1%) |
| Fingerprinting-script detection | 19 (11.9%) | 24 (11.7%) |
| Client-side vulnerabilities | 12 (7.5%) | 18 (8.7%) |
| Script performance, size, dead code | 3 (1.9%) | 8 (3.9%) |
| Unmapped detection tuples | 45 | 65 |
| Esprima (tool, in population) | 16 (10.0%) | 21 (10.2%) |
| OpenWPM (tool, in population) | 17 (10.6%) | 19 (9.2%) |
| Project Foxhound | 2 (1.3%) | 8 (3.9%) |
| PageGraph | 4 (2.5%) | 8 (3.9%) |
| Jalangi | 1 | 4 |
| Names no JS-analysis tool at all | 91 of 160 (56.9%) | 120 of 206 (58.3%) |
heuristic-rules | 80 (52.3%) | 108 (54.5%) |
dynamic-analysis | 21 (13.7%) | 33 (16.7%) |
supervised-ml | 26 (17.0%) | 31 (15.7%) |
llm | 0 (enum never fired) | 2 (1.0%) |
| Distinct ground-truth strings | 278 | 351 |
| Unmapped ground-truth tuples | 52 | 80 |
| Authors' own manual inspection | 84 (54.9%) | 102 (51.5%) |
| Filter list or tracker database | 36 (23.5%) | 44 (22.2%) |
| States some validation | 115 (75.2%) | 146 (73.7%) |
| States none anywhere | 38 (24.8%) | 52 (26.3%) |
| States headless | 28 (22.2%) | 31 (19.0%) |
| Artifact link, 2022–2024 | 46 of 59 (78.0%) vs corpus 64.7% | 53 of 68 (77.9%) vs corpus 65.0% |
| Artifact link, 2025–2026* | — | 27 of 29 (93.1%) vs corpus 76.5% |
| Assesses a law | 13 (8.1%) vs corpus 6.1% | 19 (9.2%) vs corpus 6.9% |
Moved by more than a rounding step:
- Project Foxhound 2 → 8 and PageGraph 4 → 8. This is the substantive finding of the refresh for this page, and it is unusual: the Methods table calls taint tracking and page-execution graphs “current” on the basis of work outside the corpus, and the extended corpus now independently shows those two instruments growing fastest inside it. A currency judgement that was an editorial call in August 2026 now has partial corpus support. The page says so.
- Esprima overtook OpenWPM as the most-named tool in the population, 21 to 19. Small numbers; reported as a ranking.
- The
llmclassification method fired for the first time, twice. Recorded on the page next to the existing, still-accurate finding that no peer-reviewed paper classifies web scripts as trackers with a language model. Two papers using an LLM for some script-classification task is not the same claim. - Per-1,000 density falls to 24.5 in 2025–2026, the lowest since 2010–2013. Almost certainly an artefact of the provisional years rather than a real collapse, and marked provisional in the table.
dynamic-analysis13.7% → 16.7% andstatic-analysis10.5% → 12.6%.classification.methodagrees on only 58% of papers between runs, so neither is publishable as a change.
Not changed: the granularity discussion, the Methods, and Which Ones Are Current table, the ground-truth argument, the tool maintenance table, What to Report, and every citation.
5. Folds — the ones that did not age
Recorded. Unlike fp_fold.mjs (see fingerprinting), js_fold.mjs needed no changes. Both its residues grew roughly in proportion to the population:
| Fold | Old residue | New residue | Residue per population paper |
|---|---|---|---|
Research family (detection.phenomenon) | 45 tuples / 160 papers | 65 / 206 | 0.28 → 0.32 |
Ground truth (groundTruthSource) | 52 tuples / 153 papers | 80 / 198 | 0.34 → 0.40 |
That is drift, not a break. It is worth saying why the two folds behaved so differently: fp_fold.mjs folds a subject (“what was fingerprinted”), and the 2025–2026 papers fingerprint genuinely new subjects — DPI boxes, LLMs, AR/VR apps. js_fold.mjs folds a research question and a label source, and those did not change: the field is still classifying trackers, malware and libraries, still using EasyList and its own eyes. A fold over subjects ages faster than a fold over methods. Whoever refreshes these pages next should check the subject-folds first.
Both residues are printed in full by report_javascript.mjs and are not reproduced here; they are long and one-per-paper.
5.1 Two bugs in the report script
- The last period bucket was
(y) ⇒ y >= 2022, so it swallowed 2025–2026 and reported the 2022–2024 corpus size as 3,140 instead of 1,955. The same open-ended filter was used for the artifact-release comparison. Both split into2022–2024and a starred2025–2026. - “corpus-wide 6.1%” was a hardcoded string in the legal line. On the new corpus it is 6.9% (402 of 5,859), and the hardcoded version printed the old numerator's rate beside the new population — the most dangerous kind of stale number, because it appears in freshly-computed output. Replaced with the computed value.
The identical bucket bug was present in report_fingerprinting.mjs and report_ip_classification.mjs. It is the single most common defect found in this refresh: an open-ended last bucket is correct exactly once, and then silently wrong forever.
6. Quotes checked
Recorded, 2026-08-12.
$ node scripts/quote_check.mjs --classification javascript 66 quotes checked: 34 exact, 19 partial (>=60% of 5-word windows), 13 below threshold, 0 with no full text on disk.
Five of the 13 below-threshold quotes were read by hand against paper.cols.txt — 2013/USENIX/revolver, 2017/IMC/the-ad-wars, 2017/PETS/towards-seamless-tracking-free-web, 2011/CCS/fortifying-web-based-applications, 2012/USENIX/privilege-separation-in-html5-applications — and all five are present. The last is a good example of why the automated test cannot be trusted alone; the source reads:
…ify all calls to privileged APIs (i.e., calls The parent allows the child XMLHttpRequest ac- to the chrome object) and list them in Figure 1. We be- cess to only /sqlbuddy/<filename>.php URIs. lieve that our analysi…
The extraction's “we (conservatively) identify all calls to privileged APIs (i.e., calls to the chrome object)” is correct; the two columns interleave inside the parenthesis. The other 8 were not read.
Reconstructed: the original run recorded that “each number reproduced on this page was re-located in paper.cols.txt after whitespace normalisation”, which is a stronger claim than the one above and applies to the quoted prevalence figures rather than to the schema tuples. Which numbers is not recoverable. One specific check from that run is recorded and is worth repeating here because it is the page's best cautionary tale:
- The PoPETs 2023 blanket-JS-blocking result was quoted from the paper's prose, which says “22% of functional requests and 76% of tracking requests remain”. The paper's Table 2 says tracking 1,175,033 → 265,101 (22.6% remaining) and functional 4,279,844 → 3,248,767 (75.9% remaining). The labels are transposed in the published paper.
detection[].prevalencefaithfully copied the prose, so no automated audit could catch it — only reading the table did. The page carries the corrected reading.
7. External sources
Reconstructed. Not re-verified on 2026-08-12. The page's non-corpus half is unusually large and unusually date-sensitive:
- Every tool's maintenance status was checked against its own repository commit history on 2026-08-06 and each row carries that date. Several were declared “abandoned in practice” on that evidence (AdGraph, last commit 2019-09-16). These will rot; re-check before relying on them.
- The LLM-absence finding — that no peer-reviewed paper classifies web scripts as trackers with a language model — was established by targeted search across PETS 2025/2026, USENIX Security 2025, NDSS 2025/2026, IMC 2025, TheWebConf 2025/2026, CCS 2025 and arXiv on 2026-08-06. The nearest hits (LLM-aided deobfuscation feeding a graph classifier;
humanify, which only proposes identifier names) are cited as adjacent and explicitly not on-point. The extended corpus does not overturn this: the twollmclassification tuples it added are script-classification tasks, not tracker classification, and the page distinguishes them. - The Manifest V3 timeline is from Chrome's own documentation, not a secondary source.
humanifywas checked at v3.1.1 and the footnote records that the AST rewrite is done byoxc, not the model — a correction to the obvious reading of the project's own description.
Rejected: not recorded for the original run.
8. What could not be established
- Whether the 8 unread below-threshold quotes check out. See §6.
- Whether the per-1,000 decline is real. The series peaks at 44.2 in 2014–2017 and falls to 24.5 in 2025–2026, but the last point is provisional and the page's own explanation — the topic being absorbed into tracking and supply-chain papers that no longer call themselves JavaScript analysis — is an interpretation the extraction cannot test.
- The false-positive tail of the 206. An e-voting client audit, a router-attack paper and a PHP injection-sink study are in the population and analyse JavaScript incidentally. They were left in and the page says so;
–listprints them all so a reader can judge. Nobody has audited the list paper by paper on the new corpus. - Whether
classification.methodshares are worth publishing at all. 58% run-to-run agreement is the weakest field carrying a table on this page. It is labelled as a rough share, which is the most that can honestly be done with it. - ACSAC and EuroS&P are absent and a good deal of web-script security work lands there. Stated on the page.
10. Review pass, 2026-08-12
Recorded. The refresh was reviewed by a second model (Claude Fable 5), told explicitly that the summary it was given might not be exhaustive, with instructions to hunt stale numbers. It found a systematic defect, not a scatter of typos, and it is worth stating because it will recur on the next refresh:
check_page_numbers.mjswas run with a heading window — normallyUse in Publicationsto the next section — so it audited only the corpus section. Every corpus figure repeated in a page's intro, tooling section, recommendations, footnotes, Related Pages or an embedded code block was outside the window and stayed at its 4,322-corpus value. Across the six pages 29 such figures survived the first pass.- The matcher was substring, not word-boundary, so
report.includes('59')was satisfied by11.59 bits. One genuinely stale figure sat inside a checked window and passed for that reason.
Both are fixed in scripts/check_page_numbers.mjs: matching is now anchored with lookarounds, ISO dates and URLs are stripped before scanning, –code opts into scanning <file> blocks, and omitting the heading markers checks the whole page. Run it windowed and whole-page. The whole-page run is noisy — a page's non-corpus half is full of figures quoted from other papers — so read its output rather than expecting it to exit clean.
Fixed on this page's content page as a result — and one of them is the most instructive defect in the whole refresh:
- The embedded
<file javascript js_fold.mjs>block still quoted the 4,322-corpus counts —program-analysison 959 papers,code-or-binary-analysison 1,063, LLVM 66, Soot 61, IDA Pro 36, FlowDroid 34, angr 28, Esprima 15 — two screens below the page's own table saying 1,385 / 1,484 / 101 / 81 / 62 / 48 / 39 / 23. The published, downloadable source contradicted the prose.check_page_numbers.mjsstrips<file>blocks and so could never have caught it; it now takes–code. Fixed in bothscripts/js_fold.mjsand the embedded copy, and the two were diffed afterwards. - Related-Pages shares 42.4% → 39.8% and 28.6% → 27.6%.
- “the privacy reader's own family is the largest but is barely a quarter of the field” was wrong against its own table: the largest single family is 29 of 206 = 14.1%. Rewritten to name the two families that together make 53 of 206 = 25.7%, which is what “barely a quarter” was always describing.
11. Run log
| Date | 2026-08-12 |
| Corpus at the time | data/extract/run1, 5,859 papers, 2010–2026, IEEE S&P complete at 780/780 |
| Model | Claude Opus 5, no sub-agents used for this page |
| Scope | Mechanical re-derivation. One paragraph of new prose, on Foxhound and PageGraph growth, because the refresh turned an editorial currency judgement into a partly measured one. |
| Script changes | report_javascript.mjs (bucket bug, hardcoded 6.1%, split artifact comparison), js_fold.mjs (comments only — the ground-truth string count, and, after review, the module docstring's stale corpus counts; see §10) |
| Caveats deleted | “IEEE S&P is only 43% retrieved” — 780 of 780 selected papers are now retrieved. “This corpus ends in 2024.” |
| Not deferred, but worth flagging | The llm row is 2 papers. If it is still 2 on a complete 2026, it means nothing; if it is 15, this page's Methods table needs a new row. |
| Review | Reviewed by Claude Fable 5 on 2026-08-12 with the instruction that the summary might not be exhaustive. It found the windowed-guard defect in §10 and 3 stale figures on this page plus the embedded js_fold.mjs docstring. All fixes were applied and re-saved the same day. |
