fix: resolve correctness and security findings from full-repo review#248
Conversation
Crashes and broken commands: - diff: rename _deps parameter to deps — every invocation threw ReferenceError: deps is not defined - stealth: chrome.runtime.getVersion() referenced an undefined chromeVersion identifier, throwing in the page - stealth: bind getComputedStyle proxy methods to the underlying CSSStyleDeclaration so getPropertyValue() no longer throws "Illegal invocation" on every stealth page - extract: table @ref used 0-based nthMatch with 1-based :nth-of-type, selecting the wrong (or no) table - crawl: escape regex metacharacters in --include/--exclude globs; patterns with (, [, + crashed mid-crawl and . matched any char Daemon robustness: - add a socket error handler so an abrupt client disconnect (ECONNRESET) no longer kills the daemon - defer idle shutdown while a command is still executing - propagate batch-level json flag to entries that don't set it - bound wait url/text/visible/hidden poll loops with the request timeout — abandoned loops previously polled forever - record: detach the framenavigated listener on record stop; listeners stacked across sessions and duplicated goto steps - clear withTimeout's timer once the command settles - cache in-flight scratch-page creation to avoid leaking pages under concurrent calls - use a WeakMap for per-context trace state and release per-session video state on session close - compare auth tokens with timingSafeEqual Correct results: - compliance: only use a fresh context when a URL is given (cookie audit of the current page always saw an empty jar), and capture the fresh page's requests instead of the main session's buffer - tracker-database: restrict cookie prefix matching to dynamic- suffix prefixes; front_session and similar first-party cookies were reported as Facebook/DoubleClick trackers - a11y headings: collect in document order so skip detection works - gesture: apply .nth() disambiguation to refs like other commands - recorder: emit selector fallbacks as { selector } steps so recorded flows replay; require a path boundary in base-url rewriting - crawl: pagination respects the remaining --max-pages budget and trailing-slash normalization no longer mangles query strings - config: validate login successCondition against the three keys login actually implements — textVisible et al. silently skipped verification - vrt: stop passing the pass/fail percentage threshold as compareScreenshots' per-pixel colour tolerance - cookies: fix --domain suffix matching (badexample.com no longer matches .example.com) - throttle: allow --upload/--latency without --download - subscribe: implement the advertised network/download events and honour --status - page-eval: only fall back to the unwrapped form on construction errors — runtime failures re-executed side-effectful code - do: check HTTP response status and align OPENAI_BASE_URL semantics with assert-ai (base URL includes /v1) - back/forward/intercept: swallow late rejections from the losing Promise.race branch and route.fulfill - trace/video clean: allow the documented --older-than/--dry-run flags through daemon flag validation - completions: add missing perf/security/responsive/extract commands and --webhook/--metrics flags Security hardening: - safe-pattern: reject nested unbounded quantifiers (e.g. (a+)*) instead of relying on a length cap that doesn't mitigate ReDoS - stealth: use execFileSync instead of shell interpolation when probing the configured browser binary for its version Packaging/docs: - Dockerfile: install a patchright-matching Chrome in the runtime image — the published image could only run --help - install.sh: install browsers via patchright (not upstream playwright, whose browser revisions the binary can't find) - docs/plugins.md: fix import paths ("browse/plugin" is not published; use a relative path like the bundled examples) https://claude.ai/code/session_018W3Am9a8RWjW8drwJCBNHd
|
Warning Review limit reached
More reviews will be available in 54 minutes and 43 seconds. Learn how PR review limits work. Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (35)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
dl.google.com is serving GitHub macOS runners a 138-byte stub, and patchright's installer deletes the preinstalled Chrome before it downloads — failing the install step and leaving no browser behind. Use the image's Chrome when it exists and only download when missing. https://claude.ai/code/session_018W3Am9a8RWjW8drwJCBNHd
Full-repo review fixes
A systematic review of the codebase (core daemon, config/plugins, flow machinery, all 79 command handlers, scripts/packaging, docs) surfaced ~35 high-confidence defects. This PR fixes all of them except one architectural item noted at the bottom.
Crashes and broken commands
browse diffcrashed on every invocation: the handler declared_depsbut the body referenceddeps(ReferenceErrorat runtime; tsc isn't in CI so nothing caught it).chrome.runtime.getVersion()referenced an undefinedchromeVersionidentifier, and thegetComputedStyleproxy returned unbound native methods sostyle.getPropertyValue(...)threwIllegal invocationon every stealth page — itself a bot-detection signal.extract table @refused the 0-basednthMatchwith 1-based:nth-of-type, selecting the wrong table (or none). Now indexesquerySelectorAllresults directly.--include/--excludepatterns containing(,[,+threw mid-crawl, and.acted as a wildcard (*.example.com*matchedxexamplexcom.evil). Metacharacters are now escaped.Daemon robustness
errorlistener — an abrupt client disconnect (ECONNRESET) raised an uncaught exception and killed the daemon, orphaning the browser.browse batch file.json --jsonwas ignored: the batch-leveljsonflag never propagated because entries always parsed to a concretefalse.wait url/text/visible/hiddenpoll loops never terminated — the outer timeout only abandons the promise. Timed-out waits polled the page every 100 ms for the daemon's entire lifetime. Loops are now bounded by the request timeout.record start/stopleaked aframenavigatedlistener per cycle, duplicatinggotosteps in saved flows.withTimeouttimers now cleared on settle; scratch-page creation caches the in-flight promise; trace state moved to aWeakMap; per-session video state released on session close; auth token compared withtimingSafeEqual(relevant for--listen tcp://).Wrong results
browse complianceon the current page always passed the cookie audit — it audited a freshly created (empty) context. With a URL, the tracker check read the main session's network buffer instead of the audited page's requests. Both fixed.front_sessionas Facebook (fr) andIDENTITYas DoubleClick (IDE). Prefix matching is now limited to dynamic-suffix prefixes (_ga_,_hj, …).textVisible/elementNotVisiblesuccess conditions thatwaitForSuccessdoesn't implement (it fell through and resolved immediately). Validation now only accepts the three implemented variants.{ selector }step form the flow schema already supports.a11y headingscollected headings grouped by level, masking real skip detection;gestureignored.nth()disambiguation for duplicate-name refs; crawl pagination could exceed--max-pagesby ~2x; URL normalization stripped slashes out of query strings;vrtpassed its pass/fail percentage as a per-pixel colour tolerance;cookies --domain badexample.commatched.example.com;throttle --upload/--latencywithout--downloadwas rejected;subscribesilently accepted (and defaulted to!)network/downloadevents it never listened for;page-evalre-executed side-effectful code on runtime errors;doignored HTTP error statuses and double-appended/v1toOPENAI_BASE_URL;trace clean/video cleandocumented flags were rejected by daemon flag validation; shell completions were missing four commands and several flags.Security hardening
compileSafePatternclaimed ReDoS mitigation but only capped length —(a+)*is 6 chars and hangs the daemon's event loop (flows are an untrusted input viaflow-share install). It now rejects nested unbounded quantifiers (documented as a heuristic).stealth.tsinterpolated the config-supplied browser channel into a shell command (execSync); nowexecFileSyncwith an argument vector.Packaging / docs
playwright:v1.54.1) had neither Chrome nor the chromium revision the embedded patchright 1.58.2 expects — the published image could only run--help. It now installs a matching Chrome.playwright, whose browser revisions the patchright-based release binary can't find; switched topatchright(matching setup.sh/CI).import from "browse/plugin", which doesn't exist (package is private/unpublished); now points at the relative-path pattern the bundled examples use.Tests
test/safe-pattern.test.ts,test/tracker-database.test.ts, plus regression tests for glob escaping, query-string normalization, and batchjsonfallback.bun test: 1358 pass, 0 fail (was 1343);biome checkclean; binary compiles and runs.Known limitation (intentionally not fixed here)
The ref registry (
src/refs.ts) is module-global while sessions/tabs execute concurrently: one session's snapshot/navigation can invalidate or remap another session's@erefs. Fixing it properly means moving the registry intoTabStateand threading it through ~36 call sites and ~200 test call sites — a refactor that deserves its own PR rather than riding along here. Current behavior is conservatively safe for single-session use (any navigation marks refs stale).https://claude.ai/code/session_018W3Am9a8RWjW8drwJCBNHd
Generated by Claude Code