You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Engines floor bumped: engines.node from >=22.0.0 to >=22.12.0 to match Puppeteer 25's stable require()-of-ESM requirement. Anyone running on Node 22.0–22.11 will see an npm engine warning and should upgrade.
Puppeteer dependency floor bumped: puppeteer and puppeteer-core from >=20.0.0 to >=24.0.0. Range still permits both v24 and v25 — pick via npm install puppeteer@24 or npm install puppeteer@25 according to taste. Dev lockfile moved to puppeteer@25.0.4.
Audit confirms no breaking-change impact from Puppeteer 25's executablePath/defaultArgs Promise return — neither is called in this codebase. require('puppeteer') continues to work on the now-ESM-only package thanks to Node 22.12+'s stable require-of-ESM.
Added
blockDomainsByUrl config key (top-level) — regex patterns mirroring ignoreDomainsByUrl but for active blocking. A matching request URL triggers Puppeteer request.abort() on the triggering request, the request's root domain, and all subsequent requests to that domain or its subdomains for the rest of the scan
Cloudflare aggregate stats accessible via getAggregateStats({reset}) — returns byOutcome, bySolveMethod, maxDurationMs, avgDurationMs, failures, timedOut counts; bumped on every URL regardless of debug mode
Production-level Cloudflare outcome logs: warn severity for !overallSuccess || timedOut, info for 5xx origin-error pages, debug-only on success
DNS pre-check positive-resolution shortcut — hosts already proven live by dig or whois within the cache TTL skip the c-ares pre-check via a knownResolvedHostnames index (also warmed at startup from disk-loaded dig/whois caches)
DNS pre-check skip summary now reports both NXDOMAIN-cache and positive-cache savings: DNS pre-check skipped: N URL(s) via M unresolvable host(s), N URL(s) via M resolved host(s)
[blocked-stats] per-pattern hit counters reported at scan end — surfaces which blocked patterns are doing work vs. which are stale
disable_adblock per-site config flag to escape global ad-blocking layers
capture_popups now runs whois/dig validation on matched popup URLs
Security: nettools shell-injection vector closed — exec(string) replaced with execFile(cmd, args) (no shell); config-supplied whois_server and recordType values can no longer execute commands via $()/backticks/etc.
Cloudflare detectChallengeLoop off-by-one bug — counted the current URL against itself, tripping >= 2 threshold one iteration early
Cloudflare detectChallengeLoop threshold was unreachable with default cloudflare_max_retries = 2; new exact-match path catches reload-to-same-URL loops at attempt 2
Cloudflare outcome cache namespace collision — now stored in a separate Map (was sharing keys with the detection cache, getting evicted by detection-cache pressure)
ignoreDomains dynamic Set didn't cascade to subdomains — ignoreDomainsByUrl dynamic adds now apply parent-walk just like static config (e.g. dynamically-ignored example.com now also catches cdn.example.com)
blocked / blockDomainsByUrl / ignoreDomainsByUrl regex compile failures unified — was silent-drop for *byUrl and hard-throw for blocked; now all warn loudly with [config] X pattern dropped (compile error): "..." -- regex msg and continue
adblock pattern-cache key mismatch — anchored patterns (||example.com) were missing their own cache because get/set used different keys
grep AND-logic silently dropped non-matching rules; ENOBUFS silently truncated output on large pages
Cloudflare debug logs rendered literal "undefined" when detection short-circuited on non-HTTP pages (popup → about:blank case)
Outcome label no_indicators was lying when detection short-circuited on non-HTTP page URL; now correctly reports skipped(non-http)
Cloudflare handleLegacyCheckbox selector list aligned with detection — dropped orphan .cf-turnstile input[type="checkbox"] selector that had no matching detection entry
Cloudflare safeWaitForNavigation warn was unconditional; now forceDebug-gated (was spamming stderr on phishing-bypass nav failures in production)
Cloudflare enhancedParallelChallengeDetection had zero callers — deleted
analyzeCloudflareChallenge ignored managed-challenge signals (.cf-managed-challenge, [data-cf-managed]); now folded into isChallengePresent
isChallengeCompleted double-queried the same DOM element; cached once
Various correctness fixes across compare (inline hosts-comment stripping), curl, dry-run, flowproxy (error-path bug, cookie parsing), referrer, searchstring, validate_rules modules
30+ dead exports trimmed across nettools (11), cloudflare (18 → then re-trimmed after refactor), adblock, adblock-rust, compare, dry-run
nettools disk-cache writes now atomic (tmp + rename) — surviving SIGKILL/OOM/power-loss mid-write no longer leaves a truncated file that wipes the cache on next load
Corrupt .digcache/.whoiscache files surface a [dns-cache] X was unreadable (...); starting fresh warn instead of silently resetting
dnsCacheStats.freshDig/freshWhois arrays capped at 1000 entries (FIFO) — no more unbounded growth on scans with thousands of unique fresh lookups
nettools enableDiskCache made idempotent (uses the previously-dead diskCacheEnabled flag); also warms the resolved-hostnames index from loaded entries
Cloudflare runWithRetries helper extracted — verification-challenge and phishing-warning retry harnesses collapsed from ~150 lines of duplication to thin hook-driven wrappers
Cloudflare 14-line debug block in handleVerificationChallenge collapsed to one structured line: Challenge detected: turnstile=t js=f ... title="..."
Cloudflare timing constants pruned (4 dead, 1 dead local var); waitForTimeout(page, ms) renamed to fastTimeout(ms), unused page arg dropped
Cloudflare attemptChallengeSolve post-failure diagnostic + JS challenge body.textContent now capped (2KB) per poll — was materializing MB on content-heavy pages