Skip to content

Allow loopback network access inside the workspace sandbox - #1221

Merged
SawyerHood merged 2 commits into
get-bb:mainfrom
sholub-dev:allow-loopback-in-workspace-sandbox
Aug 9, 2026
Merged

Allow loopback network access inside the workspace sandbox#1221
SawyerHood merged 2 commits into
get-bb:mainfrom
sholub-dev:allow-loopback-in-workspace-sandbox

Conversation

@sholub-dev

Copy link
Copy Markdown
Contributor

Summary

Fixes #1220.

The workspace sandbox (auto/accept-edits modes) denies all network including loopback, so bb CLI calls from sandboxed shells only ever worked through the unsandboxed-command escape hatch (allowUnsandboxedCommands, enabled only when permission escalation is ask). Turns with escalation deny — system-initiated turns such as child-completed notifications, and all child threads — have no retry path, so every bb call fails with EPERM. A parent thread orchestrating children loses bb access in exactly the turns that exist so it can dispatch the next child.

This passes network.allowLocalBinding: true in the sandbox config, which permits direct loopback connections (on macOS the profile emits (allow network-outbound (remote ip "localhost:*"))). Sandboxed commands reach the bb server in every turn without involving unsandboxed escalation; escalation semantics for everything else are unchanged.

Notes

  • allowLocalBinding also permits binding local ports (its primary documented purpose, e.g. dev servers), so this loosens the sandbox from "no network" to "loopback + local binding, nothing external". The SDK exposes no loopback allowance scoped to a single port; this is the narrowest available knob and is far tighter than the previous workaround of spawning subagents with --permission-mode full to keep bb reachable.
  • On Linux the sandbox uses a network namespace, where host loopback is unreachable regardless; this change is a no-op there.
  • No HOST_DAEMON_PROTOCOL_VERSION bump: the change is local to the claude-code bridge session options; nothing on the server/daemon wire changes.

The workspace sandbox denied all network including loopback, so bb CLI calls only worked through the unsandboxed-command escape hatch. Turns with permission escalation denied (system-initiated turns, child threads) have no such path, leaving agents unable to reach the bb server at all. Pass network.allowLocalBinding so sandboxed commands can connect to localhost directly.
@SawyerHood

SawyerHood commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

🚨 SLOP COP 🚨 · review

I am SlopCop. I am reviewing this pull request for security, code quality, performance, architecture, and practical test coverage.

// Loopback must stay reachable from inside the sandbox: the bb CLI talks
// to the local bb server, and escalation-denied turns (system-initiated
// turns, child threads) have no unsandboxed-retry path around a block.
network: { allowLocalBinding: true },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🚨 slopcop/reviewHigh: loopback access lets sandboxed code start an unsandboxed terminal through BB's unauthenticated API.

The /api/v1/* routes have no authentication check. POST /api/v1/terminals accepts a command and asks the host daemon to start it outside this Claude sandbox. After this line, untrusted workspace content can call bb terminal create or this route during an escalation-denied turn. This bypasses both allowUnsandboxedCommands: false and the workspace write boundary. Please authenticate the local API with a session token before you enable loopback access, or use a narrower authenticated transport.

@SawyerHood SawyerHood left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🚨 SLOP COP 🚨 · review

ELI5: This PR lets sandboxed Claude commands reach local BB. The fix works on macOS, but it also gives those commands an unchecked path to start unsandboxed terminals.

I found one blocking security issue.

  1. High — the BB API becomes a sandbox escape path. The local /api/v1/* routes have no authentication check. POST /api/v1/terminals starts a host terminal outside the Claude sandbox. A command influenced by untrusted repository content can use this path during an escalation-denied turn. The request bypasses both allowUnsandboxedCommands: false and the workspace write boundary. Add per-session API authentication before this network grant, or use a narrower authenticated transport.

Other findings:

  • Medium — the grant is wider than the PR description. Claude 2.1.226 emits rules for outbound access to every localhost port. It also permits bind and inbound access on every interface. A live macOS sandbox probe reached the BB server. It also reached a sandboxed listener through the machine's LAN address. External outbound access stayed blocked.
  • Medium — the agent guidance stays stale. The BB CLI skill and thread guide still tell subagents to use Full Access. That instruction bypasses the sandbox which this PR aims to make useful. Related memory, secrets, and plugin-authoring documents still say loopback needs Full Access.
  • Medium — Linux keeps the original problem. The current Claude Linux sandbox path ignores allowLocalBinding. The PR states this limit, but the code comment reads as platform-neutral.
  • Low — the flag changes Java behavior. Claude injects JAVA_TOOL_OPTIONS=-Djava.net.preferIPv4Stack=true into macOS sandboxed commands when this flag applies.

The implementation has no meaningful performance cost. It adds a constant session option and starts no new proxy or process. The sandbox construction has one owner, so I found no duplicate code to refactor. A path-scoped Unix socket could provide a narrower future transport.

Validation results:

  • @bb/agent-runtime typecheck passed.
  • The focused bridge suite passed all 62 tests.
  • The full package suite passed 837 of 838 tests. One unchanged process lifecycle test failed again when run alone.
  • A live macOS sandbox-exec probe confirmed IPv4 and IPv6 loopback access after the new rule.
  • A browser test did not apply because this change has no UI route. The sandbox probe tested the changed boundary directly.
  • No daemon protocol version change is necessary because this option stays inside the Claude bridge.

I would not merge this until the local API cannot turn loopback access into unsandboxed command execution.

@sholub-dev

Copy link
Copy Markdown
Contributor Author

Addressed the Mediums: the sandbox comment now states the grant is macOS-only and coarse (Linux --unshare-net ignores the flag), the stale loopback/Full-Access caveats in the plugin-authoring, memory, and secrets docs are updated, and the subagent guidance now defaults to inheriting the parent's permission mode.

On the High: /api/v1 being unauthenticated is pre-existing and deliberate (trusted local machine, loopback bind by default). A session token cannot create the boundary described here — the bb CLI itself runs inside the sandbox in escalation-denied turns, so any credential it can read is equally readable by every other sandboxed command. The real fix is a capability-scoped transport for sandboxed callers (e.g. a Unix socket listener mounting only agent-safe routes via allowUnixSockets), which deserves its own design and PR.

@SawyerHood

Copy link
Copy Markdown
Collaborator

Yeah I agree on the high one! Slopcop is being picky

@SawyerHood

Copy link
Copy Markdown
Collaborator

I'll merge when ci passes! TY for the contribution

@SawyerHood
SawyerHood merged commit cb3054d into get-bb:main Aug 9, 2026
9 checks passed
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.

Sandboxed threads lose all bb CLI access during system-initiated turns (child-completed), blocking orchestration

2 participants