Skip to content

fix(sandbox): elevate Agent-mode shell sandbox to allow network access#274

Merged
Hmbown merged 1 commit into
feat/v0.8.4from
fix/agent-mode-shell-network-access
May 2, 2026
Merged

fix(sandbox): elevate Agent-mode shell sandbox to allow network access#274
Hmbown merged 1 commit into
feat/v0.8.4from
fix/agent-mode-shell-network-access

Conversation

@Hmbown

@Hmbown Hmbown commented May 2, 2026

Copy link
Copy Markdown
Owner

DRAFT — security-relevant default change. Maintainer review requested.

Closes #272 (independent confirmation from external user @francofang).

Summary

In Agent mode (the default) every `exec_shell` command was wrapped in a seatbelt policy with `(deny default)` and no `(allow network-outbound)`, so DNS and outbound TCP/UDP failed at the kernel level. Symptom on macOS: "DNS resolution failed" for any URL the model tried to reach via `curl`, `yt-dlp`, package managers, …

External user repro (issue #272 from @francofang):

Start DeepSeek TUI in Agent mode (default). Ask the agent to fetch external content (e.g. YouTube). DNS fails.
Switching to YOLO mode resolves it. `config.toml` overrides have no effect.

Root cause

`engine.rs::build_tool_context` only set `elevated_sandbox_policy` for Yolo. Agent fell through to `ShellManager::sandbox_policy` = `SandboxPolicy::default()` = `WorkspaceWrite { network_access: false }`. `seatbelt::generate_policy` only emits the network-allow block when `policy.has_network_access()` is true — confirmed by the existing test `test_generate_policy_default` ("Default policy has no network").

Fix

Three-line shape change: `if mode == Yolo` → `match mode`, with Agent and Yolo both elevating to `WorkspaceWrite { network_access: true }`. Plan mode unchanged (read-only investigation never registers the shell tool).

Adds `agent_and_yolo_modes_elevate_shell_sandbox_to_allow_network` regression test so a future revert trips CI.

Trade-off the maintainer should weigh

This removes the OS-level network block from sandboxed shell commands. The remaining boundary is the application-level `NetworkPolicy` (`crates/tui/src/network_policy.rs`) plus the per-shell approval flow. Today `NetworkPolicy` only intercepts `fetch_url`, not shell commands — so a model using `curl` to reach a denied host could route around the policy. The seatbelt block was kind-of closing that hole on macOS only; it's reopened by this PR.

Options if that residual hole matters:

  1. Land this as-is for v0.8.4 — restores parity with Claude Code/Codex; macOS Seatbelt sandbox blocks outbound DNS resolution in Agent mode #272 symptom goes away. File a follow-up to teach `NetworkPolicy` about shell-level egress.
  2. Land this with a narrower policy (e.g. allow DNS + 80/443 only) — partial mitigation, more code.
  3. Reject — keep the current behavior and document "use Yolo for network workflows".

Drafted (1) since it's the smallest fix that gets the user unstuck and matches what users expect from competitors.

Test plan

  • `cargo test -p deepseek-tui --bin deepseek-tui --locked sandbox` (27/27)
  • `cargo test -p deepseek-tui --bin deepseek-tui --locked core::engine` (62/62, includes new regression)
  • `cargo fmt --all -- --check`
  • `cargo clippy -p deepseek-tui --all-targets --locked -- -D warnings`

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request enables network access for shell commands in Agent mode by elevating the sandbox policy for both Agent and Yolo modes, while keeping Plan mode restricted. A regression test was added to verify this behavior. Feedback was provided to address inaccuracies in the code comments and changelog regarding the NetworkPolicy; specifically, it was noted that the policy currently only intercepts fetch_url and does not yet provide a complete outbound boundary for shell-level traffic.

Comment on lines +1206 to +1208
// curl, yt-dlp, …) without buying the user any safety the
// application-level NetworkPolicy / approval flow doesn't already
// provide. Elevate to workspace-write + network. (#273)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

The comment suggests that the application-level NetworkPolicy provides equivalent safety to the sandbox block. However, as noted in the PR description, NetworkPolicy currently only intercepts fetch_url and does not apply to shell commands. This creates a security gap where shell tools (like curl) can bypass configured network restrictions. The comment should be updated to reflect this limitation and ideally include a TODO for implementing shell-level egress filtering.

            // curl, yt-dlp, …) without buying the user any safety the
            // approval flow doesn't already provide. Note: NetworkPolicy
            // currently only covers fetch_url; shell-level egress filtering
            // is a planned follow-up. Elevate to workspace-write + network. (#273)

Comment thread CHANGELOG.md
Comment on lines +17 to +19
investigation never registers the shell tool). The application-level
`NetworkPolicy` (`crates/tui/src/network_policy.rs`) remains the only
outbound-traffic boundary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-medium medium

This statement is technically inaccurate and may give users a false sense of security. As noted in the PR description, the NetworkPolicy currently only intercepts fetch_url and does not apply to shell commands. Therefore, it is not yet a complete "outbound-traffic boundary" for the shell tool. It would be better to clarify that shell-level enforcement is a planned follow-up.

@Hmbown Hmbown marked this pull request as ready for review May 2, 2026 01:11
Copilot AI review requested due to automatic review settings May 2, 2026 01:11
@Hmbown

Hmbown commented May 2, 2026

Copy link
Copy Markdown
Owner Author

Maintainer signed off on the trade-off (Twitter, May 1) — "going with allowing web access on agent mode is the smart move." Marked ready for review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes macOS Agent-mode exec_shell network failures by elevating the shell sandbox policy in Agent mode (previously only done in YOLO), and adds a regression test + changelog entry to prevent regressions.

Changes:

  • Update Engine::build_tool_context to elevate the shell sandbox policy for both Agent and YOLO modes (enabling outbound network).
  • Add a regression unit test asserting Agent/YOLO get an elevated sandbox policy with network access.
  • Document the fix in CHANGELOG.md.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
crates/tui/src/core/engine.rs Elevates sandbox policy for Agent + YOLO via a match on AppMode.
crates/tui/src/core/engine/tests.rs Adds regression test covering sandbox elevation for Agent/YOLO (and assumptions about Plan).
CHANGELOG.md Adds an Unreleased “Fixed” entry describing the sandbox/network behavior change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +320 to +328

// Plan mode is read-only investigation and does not register the shell
// tool, so it intentionally leaves the policy at the strict default.
assert!(
engine
.build_tool_context(AppMode::Plan, false)
.elevated_sandbox_policy
.is_none(),
);
Comment thread CHANGELOG.md Outdated
Comment on lines +11 to +19
- **Agent-mode shell exec could not reach the network** (#273) — the seatbelt
default policy denies all outbound network including DNS, so any
`exec_shell` command needing the network (`curl`, `yt-dlp`, package
managers, …) failed in Agent mode unless the user dropped to Yolo. The
engine now elevates the sandbox policy to `WorkspaceWrite { network_access:
true, … }` for both Agent and Yolo. Plan mode is unchanged (read-only
investigation never registers the shell tool). The application-level
`NetworkPolicy` (`crates/tui/src/network_policy.rs`) remains the only
outbound-traffic boundary.
Comment on lines +1199 to +1201
// Plan mode is read-only investigation; the shell tool is not
// registered, so leaving the sandbox policy at the seatbelt-strict
// default is fine.
Comment on lines +1206 to +1208
// curl, yt-dlp, …) without buying the user any safety the
// application-level NetworkPolicy / approval flow doesn't already
// provide. Elevate to workspace-write + network. (#273)
Comment on lines +295 to +299
// Regression for #273: the seatbelt-default policy denies all outbound
// network (including DNS), which broke `curl`, `yt-dlp`, package managers,
// and similar shell commands in Agent mode. Elevation must include
// network access so the application-level NetworkPolicy stays the only
// outbound boundary.
The seatbelt-default policy is `WorkspaceWrite { network_access: false }`,
which on macOS emits `(deny default)` with no `(allow network-outbound)` /
`(allow system-socket)`. Every outbound socket call from a sandboxed
shell command — including `getaddrinfo` for DNS — gets denied by the
kernel. Symptom: "DNS resolution failed" for any URL the model tries to
reach via curl, yt-dlp, package managers, etc.

Engine.build_tool_context only elevated the policy in Yolo mode, leaving
Agent mode (the default) stuck on the strict default. That's tighter
than competitors (Claude Code, Codex) without buying any safety the
application-level NetworkPolicy or the approval flow doesn't already
provide.

Switch the elevation to a `match` so:

- Plan       → no elevation (read-only investigation; shell tool not registered)
- Agent      → WorkspaceWrite { network_access: true, … }
- Yolo       → WorkspaceWrite { network_access: true, … } (unchanged)

Adds `agent_and_yolo_modes_elevate_shell_sandbox_to_allow_network` so a
future revert to the no-network default trips CI immediately.

Closes #273
@Hmbown Hmbown force-pushed the fix/agent-mode-shell-network-access branch from ae3f0a8 to d1beb69 Compare May 2, 2026 01:28
@Hmbown Hmbown merged commit 6b14e43 into feat/v0.8.4 May 2, 2026
2 checks passed
@Hmbown Hmbown deleted the fix/agent-mode-shell-network-access branch May 2, 2026 01:29
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.

2 participants