Skip to content

🤖 fix: turn off the agent-browser stream before the sandbox recipe sends the token - #7910

Merged
ThomasK33 merged 4 commits into
mainfrom
fix/agent-browser-stream-token
Nov 4, 2026
Merged

ThomasK33 merged 4 commits into
mainfrom
fix/agent-browser-stream-token

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Summary

The dev-server-sandbox skill's recipe opens the sandbox in agent-browser with the token in the URL. agent-browser 0.33.2 starts a WebSocket stream on a loopback port for every session, and that stream accepts mouse and keyboard input with no credential. Any local account could drive the authenticated page (and open a terminal in the sandbox). The recipe now turns the stream off before the token goes in. A second open port, Chrome's own DevTools port, stays open: it is documented in the skill as a limit.

Background

#7908 made the first browser open argv-free and silent. It left the stream open. Root found that nobody gets HTTP 101 on a session's stream port, and asked for the fix.

While I tested this I found that stream disable does not make the page safe. agent-browser starts Chrome with --remote-debugging-port=0, and nobody can use that port with no credential too (see Validation). A launch with --remote-debugging-pipe makes Chrome exit ("pipe file descriptors are not open"), so agent-browser has no way to drop the TCP port. This PR closes the stream and states the DevTools port as a limit. How to handle that port is a separate decision for the maintainer.

Implementation

  • .xum/skills/dev-server-sandbox/SKILL.md:
    • The recipe sets S=xum-sandbox and passes --session "$S" on every command (the bash tool does not keep AGENT_BROWSER_SESSION between calls, so later commands need --session xum-sandbox too). It opens about:blank, runs stream disable, and checks --json stream status for "enabled":false. Only then does it build the token URL and pipe it to agent-browser batch on stdin, as before. After the page loads it checks the stream again: if it came back on, the recipe closes the session and exits 1 (and says so when the close itself fails). If the first check fails, nothing is sent and the recipe exits 1 with a message. A failed batch still prints its output with token=<redacted> and exits 1.
    • The text says to close the Xum Browser tab first (it attaches to the first session it finds and turns the stream on), to rerun the recipe after close or an idle timeout (a new daemon starts with the stream on), and states the limit: Chrome's DevTools port has no credential, and on Windows the daemon's command port has none either. On a host with other accounts, use curl or xum api and do not open the authenticated page.
  • docs/AGENTS.md (Browser Automation): one paragraph that says not to open a URL that carries a credential, and points to the recipe. The built-in skill content is regenerated.

Other places checked (grep for agent-browser and token= over tracked files, including .xum/skills, .agents/skills, docs, tests/bugbash, scripts, workflows and src):

Place Opens an authenticated Xum page? Change
.xum/skills/dev-server-sandbox/SKILL.md yes the recipe above
docs/AGENTS.md generic agent-browser open <url> the paragraph above
.xum/skills/dev-desktop-sandbox/SKILL.md no (names the Electron or agent-browser workflow, no token URL) none
workflows/track1-implementation.js, workflows/track2-rlm-implementation.js no (drive turns with curl and the lockfile token) none
tests/bugbash, scripts no use of agent-browser none
.agents/skills/dogfood, .agents/skills/electron generic, vendored from vercel-labs/agent-browser (pinned by skills-lock.json) none: a local edit would break the pin
src/node/services/browser, the Browser tab product code that reads the stream of a session on purpose none

Validation

I ran the recipe as written (extracted from the skill) against make dev-server-sandbox with a token of Xq+9/aZ=_proof&k#z, and probed as nobody (sudo -n -u nobody):

  • Control, a plain session: the stream port answers nobody with HTTP/1.1 101 Switching Protocols.
  • Recipe: a shim in front of agent-browser recorded the stream port just before stream disable (the page is about:blank then): nobody got 101 on it. After the recipe, nobody got Connection refused on that port, and stream status said Streaming disabled. The session's daemon had no TCP listener left.
  • stream disable closed a client that was already connected (the client saw the server close).
  • The recipe printed nothing on stdout and 33 bytes on stderr ([agent-browser] launched browser), with 0 hits for the raw and the URL-encoded token. The page loaded authenticated (the first-run provider dialog, not "Authentication Required") and its URL had no token.
  • Stand-ins for agent-browser (they log the calls): the stream cannot be turned off (exit 1, no batch call, 0 token hits), the stream turns on after the batch (exit 1, session closed), the batch echoes the URL with exit 0 (nothing printed) and with exit 1 (token=<redacted>, exit 1). Every call carried --session.
  • The limit, as nobody: the session's Chrome port still answered GET /json/version with HTTP 200. In a separate check, nobody also finished the CDP WebSocket handshake and got a reply to Target.getTargets.

Risks

  • The stream is the live view that Xum's Browser tab can show for an agent-browser session. A session that follows this recipe has no stream, so a Xum app on the same host cannot show it.
  • A Xum app that attaches the session in its Browser tab turns the stream back on (ensureSessionAttachable in AgentBrowserSessionDiscoveryService, and the tab attaches by itself). The skill says to close the tab first, and the recipe's second check catches a re-enable after the page loads but cannot prevent one in the short gap between the checks.
  • A user who skips the recipe is not protected. The recipe changes the documented steps, not the tool.
  • The DevTools port is open for the whole life of the session. This PR does not change that.

Generated with xum • Model: anthropic:claude-sonnet-5-5 • Thinking: xhigh • Cost: $38.49

…nds the token

agent-browser starts a credential-less WebSocket stream per session. The recipe now opens about:blank, turns the stream off, checks that it is off, and only then sends the token URL. The skill states the Chrome DevTools port limit. AGENTS.md says not to open credential URLs directly.
@mintlify

mintlify Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
Mux 🟢 Ready View Preview Nov 4, 2026, 12:37 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-04T01:30:55.486876Z 25b6a35 Manual request
🔒 Security Review ✅ Completed 2026-11-04T01:32:37.507290Z 25b6a35 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

Head: b972058

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

🟢 e2e stories (Haiku): 14 passed

22 agent steps · 7 replayed from cache · 15 model calls · 47.1k tokens (23% cached)
Spend: $0.09 of the $1.00 cap (proxy ledger)

All 14 tests in 9 files
Test Agent Time
🟢 chatRestart.e2e.ts · 1 passed 1 step · 1 call 5.2s
🟢 a chat survives a restart of the server 1 step · 1 call 5.2s
🟢 compaction.e2e.ts · 1 passed 1 step · 1 call 4.3s
🟢 /compact replaces the old chat with a summary 1 step · 1 call 4.3s
🟢 pluginTrustRestart.e2e.ts · 1 passed 4 steps · 2 calls 10.2s
🟢 a trusted plugin hook stays trusted after the server restarts 4 steps · 2 calls 10.2s
🟢 settingsRoundTrip.e2e.ts · 1 passed 2 steps · 1 call 8.6s
🟢 a chat survives trips through Settings 2 steps · 1 call 8.6s
🟢 sidebarPerWorkspace.e2e.ts · 1 passed 4 steps · 1 call 4.0s
🟢 a new workspace starts with its right sidebar collapsed while another keeps it open 4 steps · 1 call 4.0s
🟢 smoke.e2e.ts · 1 passed 2 steps · 1 call 2.7s
🟢 the agent opens the playground workspace 2 steps · 1 call 2.7s
🟢 streamErrors.e2e.ts · 1 passed 1 step · 1 call 6.9s
🟢 stream errors show in the chat, and the chat recovers 1 step · 1 call 6.9s
🟢 todoNudge.e2e.ts · 1 passed 1 step · 1 call 3.0s
🟢 the agent finishes open TODO items after the turn-end nudge 1 step · 1 call 3.0s
🟢 touchAlignment.e2e.ts · 6 passed 6 steps · 6 calls 26.3s
🟢 the Settings close button is level with the title on a touch screen 390px wide 1 step · 1 call 4.5s
🟢 the Settings close button is level with the title on a touch screen 768px wide 1 step · 1 call 4.0s
🟢 Backup settings checkboxes are small and level with their labels on a touch phone 1 step · 1 call 4.2s
🟢 the heartbeat checkbox is small and level with its label on a touch phone 1 step · 1 call 3.1s
🟢 a reply's model and time stay on one line on a touch phone 1 step · 1 call 3.8s
🟢 the workspace actions menu stays on the title row on a touch phone 1 step · 1 call 6.7s

e2e 0.20.0 · 1m 15s · web · run artifacts

🟢 e2e Electron stories (Haiku): 3 passed

3 agent steps · 3 model calls · 7.9k tokens (22% cached)
Spend: $0.02 of the $1.00 cap (proxy ledger)

All 3 tests in 3 files
Test Agent Time
🟢 electron/deepLink.e2e.ts · 1 passed 1 step · 1 call 5.2s
🟢 a deep link of a second launch starts a chat in the running app 1 step · 1 call 5.2s
🟢 electron/menuBar.e2e.ts · 1 passed 1 step · 1 call 5.6s
🟢 the workspace menu bar is the desktop title bar 1 step · 1 call 5.6s
🟢 electron/smoke.e2e.ts · 1 passed 1 step · 1 call 7.7s
🟢 Xum Electron opens the playground workspace 1 step · 1 call 7.7s

e2e 0.20.0 · 20.8s · electron · run artifacts

🟢 e2e agent repros (Haiku): no tests selected

Spend: $0.00 of the $1.00 cap (proxy ledger)

e2e 0.20.0 · 5.8s · 2 targets (web, phone) · run artifacts

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: b972058141

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b972058141

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .xum/skills/dev-server-sandbox/SKILL.md Resolved
Comment thread .xum/skills/dev-server-sandbox/SKILL.md Resolved
Comment thread .xum/skills/dev-server-sandbox/SKILL.md Resolved
…-attachment

Codex review on #7910. The bash tool drops AGENT_BROWSER_SESSION between calls, so the recipe passes --session on every command and the text says to do the same later. The Xum Browser tab attaches a session by itself and turns its stream on, so the text says to close the tab and the recipe checks the stream again after the page loads. The limit names the Windows daemon port.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c2adfcf1bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .xum/skills/dev-server-sandbox/SKILL.md Resolved
Codex review on #7910. A failing close no longer prints that the session was closed.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Head: 25b6a35

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 25b6a35ca0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 25b6a35ca0

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

Head: 25b6a35

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 25b6a35ca0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 25b6a35ca0

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit fffbbe1 Nov 4, 2026
64 of 67 checks passed
@ThomasK33
ThomasK33 deleted the fix/agent-browser-stream-token branch November 4, 2026 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant