-
-
Notifications
You must be signed in to change notification settings - Fork 68.8k
[Bug]: Sandbox browser bridge is started without auth token, allowing cross-session local takeover #11023
Description
CVSS Assessment
| Metric | Value |
|---|---|
| Score | 9.2 / 10.0 |
| Severity | Critical |
| Vector | CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:L |
Summary
The sandbox browser bridge supports bearer-token protection, but the primary sandbox startup path calls it without an authToken. This creates an unauthenticated per-session browser control API, allowing any local process to interact with another session’s sandboxed browser state.
Affected Code
File: src/browser/bridge-server.ts:33
const authToken = params.authToken?.trim();
if (authToken) {
app.use((req, res, next) => {
const auth = String(req.headers.authorization ?? "").trim();
if (auth === `Bearer ${authToken}`) {
return next();
}
res.status(401).send("Unauthorized");
});
}Sandbox path starts bridge without passing authToken:
File: src/agents/sandbox/browser.ts:192
return await startBrowserBridgeServer({
resolved: buildSandboxBrowserResolvedConfig({
controlPort: 0,
cdpPort: mappedCdp,
headless: params.cfg.browser.headless,
evaluateEnabled: params.evaluateEnabled ?? DEFAULT_BROWSER_EVALUATE_ENABLED,
}),
onEnsureAttachTarget,
});Unauthenticated routes include sensitive actions:
File: src/browser/routes/agent.act.ts:447
app.post("/download", async (req, res) => {
// ...
const out = toStringOrEmpty(body.path);
// ...
const result = await pw.downloadViaPlaywright({
cdpUrl: profileCtx.profile.cdpUrl,
targetId: tab.targetId,
ref,
path: out,Attack Surface
How is this reached?
- Network (HTTP/WebSocket endpoint, API call)
- Adjacent Network (same LAN, requires network proximity)
- Local (local file, CLI argument, environment variable)
- Physical (requires physical access to machine)
Authentication required?
- None (unauthenticated/public access)
- Low (any authenticated user)
- High (admin/privileged user only)
Entry point: Sandbox browser bridge URL (bridgeUrl) returned by ensureSandboxBrowser() and served by startBrowserBridgeServer().
Exploit Conditions
Complexity:
- Low (no special conditions, works reliably)
- High (requires race condition, specific config, or timing)
User interaction:
- None (automatic, no victim action needed)
- Required (victim must click, visit, or perform action)
Prerequisites: Sandbox browser mode enabled and a session has started a bridge (which binds a local port). Attacker only needs local process execution on the same machine.
Impact Assessment
Scope:
- Unchanged (impact limited to vulnerable component)
- Changed (can affect other components, escape sandbox)
What can an attacker do?
| Impact Type | Level | Description |
|---|---|---|
| Confidentiality | High | Read cookies/storage/network response bodies from another session’s sandbox browser context |
| Integrity | High | Drive browser actions and alter browser state for another session; leverage file-writing browser actions (e.g., download path control) |
| Availability | Low | Interrupt or reset active browser workflows for other sessions |
Steps to Reproduce
- Enable sandbox browser mode and trigger a session that initializes
ensureSandboxBrowser(). - Obtain the session bridge URL (e.g., from runtime metadata/state where
bridgeUrlis recorded). - Call bridge endpoints without credentials:
curl <bridgeUrl>/profilescurl -X POST <bridgeUrl>/startcurl -X POST <bridgeUrl>/tabs/open -H 'Content-Type: application/json' -d '{"url":"https://example.com"}'
- Access sensitive state without credentials:
curl "<bridgeUrl>/cookies?targetId=<returnedTargetId>"
- Observe that no
Authorizationheader is required despite bridge support for bearer auth.
Recommended Fix
- Generate a cryptographically strong per-bridge token when creating sandbox bridges.
- Pass that token via
authTokentostartBrowserBridgeServer(...)and enforce it for all requests. - Scope token disclosure only to the owning session context, and rotate token when bridge is recreated.
- Optionally reject bridge startup if auth token setup fails.