We Scanned 10 of the Biggest JavaScript Repos. Here's What We Found — Including Our Own Mistakes.
Before launching Thuban, we pointed it at Express, Next.js, Strapi, Signal Desktop and six more of the most popular open-source projects in the JavaScript ecosystem. This is the full, honest breakdown: the real findings, the borderline calls, and the five categories of false positives we found in our own scanner — and fixed before publishing this.
*9 production repos + OWASP Juice Shop, which is intentionally vulnerable and counted separately (see below).
Why we're publishing our own scanner's mistakes
Every developer's first objection to a code scanner is the same: "it's probably all false positives." Fair. Most scanners earn that reputation.
So instead of cherry-picking our best results, we're showing you the whole audit — including the moment our scanner flagged 213 issues in cal.com and 196 of them were wrong. We fixed the root cause, re-scanned, and cal.com dropped to 26 legitimate findings. That fix — and four others like it — shipped before this post did.
The results
| Repo | Stars | Files | Issues | Scan Time | Notable |
|---|---|---|---|---|---|
| Express | 66k | 100 | 212 | 874ms | XSS patterns in examples, hardcoded example passwords |
| Lodash | 60k | 51 | 514 | 3.6s | Deep nesting, complexity hotspots |
| Fastify | 33k | 100 | 125 | 1.3s | Complexity warnings |
| Next.js | 130k | 100 | 202 | 5.7s | Phantom imports in CI scripts |
| n8n | 50k | 100 | 399 | 2.8s | 295 magic numbers (mostly JSON config — noise, see below) |
| Strapi | 65k | 100 | 198 | 1.6s | SSL validation disabled in setup script |
| cal.com | 33k | 100 | 26 | 1.1s | Clean after our path-alias fix |
| Signal Desktop | 15k | 100 | 129 | 1.1s | Deep nesting, quality warnings |
| LangChain.js | 13k | 100 | 151 | 1.1s | Missing constants, perf warnings |
| Juice Shop* | 10k | 100 | 85 | 651ms | SQL injection everywhere — by design |
*OWASP Juice Shop is a deliberately vulnerable training application. Thuban correctly flagged its planted vulnerabilities — a validation of detection capability, not a finding against the project. It is excluded from the 1,956 headline count.
The findings that matter
Strapi: SSL certificate validation disabled REAL
examples/complex/scripts/setup-v4-project.js — when database SSL is enabled, certificate validation is turned off:
ssl: env.bool('DATABASE_SSL', false)
? { rejectUnauthorized: false }
: false,
This permits man-in-the-middle attacks on the database connection. Important context: this is in an example setup script, not Strapi's production runtime — but setup scripts get copy-pasted into production configs constantly. The fix is one line: rejectUnauthorized: true or a proper CA certificate.
Express: XSS-shaped patterns in official examples BORDERLINE
res.send('users ' + names.slice(from, to + 1).join(', '));
The specific example isn't exploitable — the output comes from a hardcoded array. But res.send(user_influenced_data) without sanitisation is the exact pattern that becomes reflected XSS when a developer swaps in real data. Express examples are how millions of developers learn Node. Of 25 taint findings in Express, 23 were in test files (expected); 2 were in examples.
Express: hardcoded password in the auth example EXPECTED
hash({ password: 'foobar' }, function (err, pass, salt, hash) {
Example code with hardcoded credentials gets copy-pasted. The comment says "foobar is the pass here" — but how many people change it?
n8n: 295 magic numbers NOISE
Our magic-number rule fired on JSON configuration files, which are naturally full of numbers. That's a scanner limitation, not an n8n problem — it's on our fix list for v0.4.7. We're counting it against ourselves, not them.
The 5 false positives we fixed in our own scanner
This is the section most scanner vendors would delete. We think it's the most important one.
Fix 1 — node: protocol imports flagged as hallucinations
require('node:fs') — standard since Node 16 — was flagged as a phantom import.
Eliminated ~20 false positives across Fastify, Next.js, Signal.
Fix 2 — scanning inside comments
Patterns like eval() and SQL-injection regexes matched code examples inside JSDoc comments. Comment lines are now skipped except for rules designed for them (TODO/FIXME).
Lodash dropped 611 → 514 issues.
Fix 3 — sanitiser blindness
Data passing through escapeHtml(), DOMPurify.sanitize() and 20+ other sanitisers was still flagged as XSS. Taint analysis now recognises them.
Eliminated 3 false XSS findings in Express.
Fix 4 — self-referencing imports
Fastify's own tests doing require('fastify') were flagged as phantom imports. The scanner now walks up the directory tree checking package.json names, including workspaces.
Eliminated 7 false positives in Fastify.
Fix 5 — TypeScript path aliases
import X from '@/lib/thing' is a build-tool alias, not an npm package. The scanner treated it as a hallucinated dependency.
cal.com dropped 213 → 26 issues. The single biggest accuracy win of the audit.
What's still on our fix list
Full transparency — four known false-positive categories remain, targeted for v0.4.7:
| Category | Plan |
|---|---|
| Hardcoded-key detection firing on test fixtures | Exclude test/, *.spec.* from SEC001 |
| Magic numbers in JSON config files | Exclude .json from QUAL005 |
| Monorepo workspace siblings flagged as phantom imports | Resolve across all workspace packages |
| "File too large" warnings on big JSON files | Silence for non-code files |
Until then, any finding can be suppressed with // thuban-ignore.
What this proves
1. The scanner finds real issues. A genuine SSL misconfiguration in a 65k-star project's tooling. XSS-shaped teaching patterns in the framework everyone learns from. And it correctly identified every planted vulnerability in OWASP's deliberately vulnerable training app.
2. It's fast. 951 files, 10 repos, 19.8 seconds total. Roughly 2 seconds per repo.
3. We eat our own dog food. Five false positive categories found, fixed, and disclosed — before launch, not after your bug report.
Run the same audit on your own code
Everything runs locally. Your code never leaves your machine.
Get Thuban
Methodology: Thuban v0.4.6, default ruleset (69 rules), capped at 100 files per repo, scanned July 2026 from each repo's default branch. Juice Shop findings excluded from headline counts as intentional. Strapi finding disclosed to their security team prior to publication. Questions or corrections: we want them — open an issue.