From d86c9c4be20d732fb4e09a69e94f953543a6f318 Mon Sep 17 00:00:00 2001 From: leeguooooo Date: Wed, 17 Jun 2026 13:31:49 +0900 Subject: [PATCH] =?UTF-8?q?fix(relay):=20don't=20adopt=20foreign=20tabs/po?= =?UTF-8?q?p-ups=20on=20click=20=E2=80=94=20completes=20multi-agent=20isol?= =?UTF-8?q?ation=20(#last=20hole)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After strict isolation (v1.5.16) a session's tracked set is only its OWN tabs, so in `adopt_newly_opened` (run after every click to follow a pop-up) EVERY foreign tab looks "new" relative to the session's `before` set and got adopted — a click-heavy flow on a busy shared Chrome pulled other agents'/the user's tabs (github, Lark, iphone-use) into the session mid-flow. A pop-up the agent itself opened can't be told apart from a foreign tab over the relay (the synthesized targetInfo carries no opener/window/group), so on the relay `adopt_newly_opened` now adopts nothing: the agent drives only tabs it explicitly created; pop-ups (OAuth/login windows) are the user's. Launched browsers (every tab ours) still follow pop-ups. Verified live: a fresh click-heavy relay session stays clean (only its own tabs), and 5 concurrent agents churning tabs show zero cross-agent drift. --- cli/src/native/browser.rs | 12 ++++++++++++ skill-data/core/SKILL.md | 16 ++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/cli/src/native/browser.rs b/cli/src/native/browser.rs index ca39ee0..9bad985 100644 --- a/cli/src/native/browser.rs +++ b/cli/src/native/browser.rs @@ -1560,6 +1560,18 @@ impl BrowserManager { /// the active tab, per #7/#8.1); the caller surfaces it so the agent knows a /// tab opened instead of seeing the old page (issue #24-A). pub async fn adopt_newly_opened(&mut self, before: &HashSet) -> Option { + // STRICT MULTI-AGENT ISOLATION: on the relay this session's `before` set is + // only its OWN tabs, so EVERY foreign tab (the user's, other agents') looks + // "new" relative to it and would be adopted here — exactly the leak where a + // concurrent agent's tabs (github/Lark/iphone-use) showed up in this + // session mid-flow. A tab the agent itself opened (a pop-up) can't be + // distinguished from a foreign tab over the relay (no opener/window/group + // in the synthesized targetInfo), so don't adopt anything: the agent drives + // only tabs it explicitly created, and pop-ups (e.g. an OAuth/login window) + // are the user's. A launched browser (every tab ours) still follows pop-ups. + if self.agent_group().is_some() { + return None; + } let result: GetTargetsResult = self .client .send_command_typed("Target.getTargets", &json!({}), None) diff --git a/skill-data/core/SKILL.md b/skill-data/core/SKILL.md index ac536a2..df6ab93 100644 --- a/skill-data/core/SKILL.md +++ b/skill-data/core/SKILL.md @@ -134,14 +134,14 @@ drives the page without moving the user's mouse/keyboard, so it doesn't fight them for control. **Strict multi-agent isolation.** A session over the relay tracks and drives -**only the tabs it created** (its own group) plus pop-ups its own clicks open. It -does **not** adopt the user's existing tabs or other agents' tabs, so several -agents (and other tools opening tabs) can work in the same real Chrome -concurrently without ever dropping or stealing each other's tabs — another -agent's tab churn can't make your bound tab vanish or drift your commands onto the -wrong page. Consequence: `tab list` shows only *your* session's tabs; to drive a -specific pre-existing tab, navigate to it in your own tab instead of expecting it -in the list. **Anti-detection ranking: this real logged-in Chrome (extension +**only the tabs it created** (its own group). It does **not** adopt the user's +existing tabs, other agents' tabs, or pop-ups (e.g. an OAuth/login window — that's +the user's), so several agents (and other tools opening tabs) can work in the same +real Chrome concurrently without ever dropping or stealing each other's tabs — +another agent's tab churn can't make your bound tab vanish or drift your commands +onto the wrong page. Consequence: `tab list` shows only *your* session's tabs; to +drive a specific page, navigate to it in your own tab instead of expecting a +pre-existing or popped-up tab to appear in the list. **Anti-detection ranking: this real logged-in Chrome (extension connect) > a headed launched browser > headless (forbidden).** A genuine human browser has no headless/automation tells at all, so prefer it for anything anti-bot-sensitive.