From ea73027e2808d2b628b126e76127e1b5ee61bde4 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 17 Apr 2026 06:05:09 +0800 Subject: [PATCH] fix(browse): document CDP debug port security + log Chrome version on v20 fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #892 per Codex outside-voice review. Two small additions to the Windows v20 App-Bound Encryption CDP fallback: 1. Inline comment documenting the deliberate security posture of the --remote-debugging-port. Chrome binds it to 127.0.0.1 by default, so the threat model is local-user-only (which is no worse than baseline — local attackers can already read the cookie DB). Random port 9222-9321 is for collision avoidance, not security. Chrome is always killed in finally. 2. One-time Chrome version log on CDP entry via /json/version. When Chrome inevitably changes v20 key format or /json/list shape in a future major version, logs will show exactly which version users are hitting. Co-Authored-By: Claude Opus 4.7 (1M context) --- browse/src/cookie-import-browser.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/browse/src/cookie-import-browser.ts b/browse/src/cookie-import-browser.ts index 59bb0791..aad98e8b 100644 --- a/browse/src/cookie-import-browser.ts +++ b/browse/src/cookie-import-browser.ts @@ -827,7 +827,21 @@ export async function importCookiesViaCdp( if (!dataDir) throw new CookieImportError(`No Windows data dir for ${browser.name}`, 'not_installed'); const userDataDir = path.join(getBaseDir('win32'), dataDir); - // Launch Chrome headless with remote debugging on the real profile + // Launch Chrome headless with remote debugging on the real profile. + // + // Security posture of the debug port: + // - Chrome binds --remote-debugging-port to 127.0.0.1 by default. We rely + // on that — the port is NOT exposed to the network. Any local process + // running as the same user could connect and read cookies, but if an + // attacker already has local-user access they can read the cookie DB + // directly. Threat model: no worse than baseline. + // - Port is randomized in [9222, 9321] to avoid collisions with other + // Chrome-based tools the user may have open. Not cryptographic. + // - Chrome is always killed in the finally block below (even on crash). + // + // Debugging note: if this path starts failing after a Chrome update, + // check the Chrome version logged below — Chrome's ABE key format (v20) + // or /json/list shape can change between major versions. const debugPort = 9222 + Math.floor(Math.random() * 100); const chromeProc = Bun.spawn([ exePath, @@ -847,8 +861,20 @@ export async function importCookiesViaCdp( // Network.getAllCookies is only available on page targets, not browser. let wsUrl: string | null = null; const startTime = Date.now(); + let loggedVersion = false; while (Date.now() - startTime < 15_000) { try { + // One-time version log for future diagnostics when Chrome changes v20 format. + if (!loggedVersion) { + try { + const versionResp = await fetch(`http://127.0.0.1:${debugPort}/json/version`); + if (versionResp.ok) { + const v = await versionResp.json() as { Browser?: string }; + console.log(`[cookie-import] CDP fallback: ${browser.name} ${v.Browser || 'unknown version'}`); + loggedVersion = true; + } + } catch {} + } const resp = await fetch(`http://127.0.0.1:${debugPort}/json/list`); if (resp.ok) { const targets = await resp.json() as Array<{ type: string; webSocketDebuggerUrl?: string }>;