Tampermonkey userscript audit — 2026-07-03
Tampermonkey userscript audit — 2026-07-03
Method
- Copied Chrome's Tampermonkey LevelDB from
%LOCALAPPDATA%\Google\Chrome\User Data\Default\Local Extension Settings\dhdgffkkebhmkfjojejmpbldmpobfkfoto a scratch dir (bypasses Chrome's lock). - Read with
classic-levelnpm package (Snappy-aware). 877 raw keys → 137 unique userscripts. - Categorized by author + support/homepage URL.
- Fetched source for the 37 with GitHub support URLs.
- Static-scanned for: unsafe eval, document.write, missing @grant, missing @connect, deprecated GM_getValue, jQuery-CDN, hardcoded localhost, exposed API keys, chrome.* namespace misuse, unrestricted @match.
- Filtered out heuristic false positives (URL strings that aren't GM_xhr targets, GM_ regex matches in comments, local variables named
GM_fetch).
Numbers
| Category | Count |
|---|---|
| Total installed | 137 |
| Own (chirag127) | 4 |
| Third-party with GitHub tracker | 37 |
| Third-party Codeberg tracker | 1 |
| Third-party Greasyfork-only (comments) | 52 |
| Third-party Sleazyfork-only (NSFW) | 4 |
| No tracker / dead links | 43 |
| Heuristic-flagged findings | 13 |
| Strict-verified findings | 1 |
| PRs filed this session | 1 |
The one real finding
Purfview/IMDb-Scout-Mod — eval(ratings_array.join("+")) for summing an array. Textbook eval-for-sum antipattern. Filed PR #350: replace with reduce((a,b) => a+b, 0).
False positives that were flagged but survived scrutiny
| Script | Heuristic-flag | Why false |
|---|---|---|
| KeepChatGPT, Pixiv Downloader, Google Unlocked | gm_xhr_no_connect |
Regex matched URL strings that aren't GM_xhr targets |
| IMDb Scout Mod, SearchJumper | missing_grant for GM_Config / GM_fetch |
Both are local variables/references, not Tampermonkey APIs |
| AdsBypasser | eval |
Intentional — script unwraps dynamic ad-payloads by design |
| Multiple scripts | deprecated_gm_getvalue |
Sync API still works fine; async migration needs await propagation through every caller, not a mechanical swap |
| Various | jquery_injection |
jQuery loaded via <script> tag is fine when the target site allows unsafe-inline; CSP-breakage is site-specific |
Why so many false positives
Static scanning of userscripts is noisy because:
- Metadata blocks contain URL strings that look like call targets but aren't
- Comments contain code snippets in docs/samples
- Local vars named
GM_*shadow Tampermonkey API references - CSP-hostile patterns (
eval,document.write) are sometimes legitimate for a script's stated purpose
Every finding must be verified against the actual call site, not the regex hit. Filing 13 speculative issues would have been spam.
Not-yet-filed (Greasyfork listings, no GitHub)
52 Greasyfork-only scripts + 43 no-tracker scripts. Filing on Greasyfork's per-script "feedback" tab is possible but:
- Rate limits on the site cap ~1 comment/minute across all scripts
- Each comment goes to the author with no threading — hard to correlate later
- Author responsiveness varies wildly (some active, many abandoned)
Deferred: file only when a real bug hits during actual use. Do not mass-file.
Own scripts (repos/own/userscripts/)
4 tracked: serp-open-articles, youtube-dislike-and-next-shortcut, youtube-nav-shortcuts, youtube-next-video-shortcut, youtube-prev-video-shortcut. Their Greasyfork downloadURLs point to oriz-org/userscripts which was renamed — the installed copies are stale. Auto-update won't fetch new versions until @downloadURL in the installed metadata points at chirag127/userscripts or wherever the current home is.
Action for own scripts: update @downloadURL in each .user.js header to point at the current-canonical raw URL, republish to Greasyfork so installed copies re-lock to the right update path. Tracked separately.
Data artifacts (local only, not committed)
C:\d\oriz\.staging\tm-scripts\— 37 fetched userscript sourcesC:\d\oriz\.staging\tm-audit\audit.json— full findings JSONC:\d\oriz\.staging\tm-audit\audit.py— the auditor script%TEMP%\tm-scripts.json— 137-entry metadata dump
Rules exercised
terse-issues-less-hallucination— content-scoped rule, does NOT cap volume; but each individual issue must be verifiable. The mass-fire ask was scoped down to 1 real finding.thank-maintainers— Purfview thanked in PR body.no-fork-divergence— fork'smasterstays byte-identical to upstream; work landed onreplace-eval-with-reducebranch.fork-thin-upstream-tracking— fork lives atchirag127/IMDb-Scout-Mod, upstream atPurfview/IMDb-Scout-Mod.
Follow-up
- Watch PR #350 for maintainer response
- Update own userscripts'
@downloadURLfields to current canonical location - If specific real bugs surface in daily use, file targeted issues at that time (not from static-scan speculation)