Your Agent Is Sandboxed. Why Can It Still Reach the Host?

A workspace-write policy can still leave a hidden route through host PIDs and /proc. See the fixed versions and a safe PID-namespace check.

You give a coding Agent /srv/app and set its policy to workspace-write. The intended boundary sounds straightforward:

  • code, lockfiles, and test output under /srv/app may change;
  • /etc, other projects, and host services should remain read-only.

An older DeepSeek Harness Bubblewrap profile left out a separate layer of isolation. A confined command could still see host processes, and Linux procfs can expose the filesystem view seen by one of those processes. Put those two facts together and, on hosts where the remaining access checks allow it, the Agent may reach a file view outside the path boundary you thought you had configured.

The chain has four links:

Four-step path from workspace-write to host process visibility, procfs magic links, and a possible access outside the workspace

Figure 1: workspace-write did not fail by itself. The old profile also exposed host PIDs, leaving procfs as a second route across the boundary.

DeepSeek Harness fixed the issue in dsh-v0.1.1-rc.1, released on August 21, 2026. The current npm release as of August 24 is 0.1.1-rc.2, and its tag contains the fix commit. A deployment still on 0.1.0-rc.8 or an earlier source revision needs more than a quick “the Agent starts successfully” check.

workspace-write controls file effects, not process visibility

workspace-write tells Harness which paths a command may modify. It does not mean the command is fully separated from every host capability.

On Linux, Harness can run an Agent’s shell commands through Bubblewrap. Bubblewrap is a low-level sandbox construction tool: its caller combines namespaces, mounts, and other arguments to create a particular boundary. A namespace is a Linux mechanism that gives a process its own view of something such as process IDs or mounts.

Bubblewrap does not decide on its own which host processes should be visible, whether the network should be available, or which directories should be writable. Its README is explicit that the sandbox’s security properties come from the arguments passed by the caller.

The old Harness profile did establish a useful file boundary. It bound the host root as read-only and made the workspace writable. The missing piece was process isolation: it mounted a fresh /proc without creating a private PID namespace.

A PID namespace decides which processes a command can see and which process numbers they receive. When the sandbox and host share that namespace, the sandbox’s /proc can still list host PIDs. A new procfs mount does not help if it is populated from the same process view.

That is why a setting about writable directories turns into a Linux process-isolation problem. The normal path to a host file may be read-only, but the command can still see an object that provides another path to the same underlying file view.

The hidden route starts with a host PID

Linux creates a /proc/<pid>/ directory for every visible process. Suppose a host service has PID 4182. The entry /proc/4182/root is not merely a conventional symlink to /. It represents the root directory as process 4182 sees it.

The distinction matters because the Agent command and the host service may see different mount layouts. Inside Bubblewrap, / has been rebuilt around the sandbox policy. For the host service, / is still the host’s filesystem view. The Linux proc_pid_root(5) manual says that dereferencing /proc/<pid>/root provides the target process’s view of the filesystem, including its namespaces and per-process mounts.

The old profile could therefore expose a path like this:

confined Agent command
  -> sees host PID 4182
  -> follows /proc/4182/root
  -> reaches the root view seen by the host service
  -> may encounter files outside the workspace policy's normal path

Other procfs “magic links,” including cwd, fd, and exe, can connect process-specific views in similar ways.

The word “may” is essential. Linux applies a ptrace access check when /proc/<pid>/root is dereferenced. Kernel settings, process credentials, container configuration, and whether the target process is dumpable can all change the result. One host may deny the access while another same-user process is reachable.

There is no published CVE, CVSS score, or complete affected-version table in the release notes. This is also not evidence that every application using Bubblewrap has a generic “container escape.” The issue is a specific combination of arguments in an older DeepSeek Harness profile.

A denied access test is not proof that the boundary is sound

This bug is easy to miss because ordinary file checks can all look correct. The Agent can create a file in /srv/app; a direct write to /etc fails; tests finish without an obvious error. If the test never follows a host process’s procfs path, the result only proves that the normal path is restricted.

A second access check may also hide the configuration error. If ptrace rules deny one attempt on a test machine, it is tempting to conclude that /proc/<pid>/root is harmless. Change the credentials, target process, kernel policy, or outer container and the result can change.

That is not a reliable sandbox boundary. The profile should remove the route it did not intend to expose, rather than depend on a separate host rule happening to reject a particular attempt. DeepSeek Harness’s implementation note treats ptrace and procfs ownership checks as defense in depth, not a replacement for a private process view.

The fix gives Bubblewrap a private process view

The fix commit adds --unshare-pid to every Bubblewrap profile and mounts /proc for the resulting private PID namespace.

DeepSeek Harness before the fix sharing the host PID namespace and after the fix using a private PID namespace

Figure 2: After the fix, the Agent still manages its own descendants, but host processes and their procfs paths are absent from the sandbox view.

The fix does not remove procfs. A confined command still needs to observe, terminate, and wait for the child processes it starts. The difference is that host PID 4182 is no longer present, so the corresponding /proc/4182/root, cwd, and fd entries are not present either.

Official end-to-end tests cover both read-only and workspace-write. They require the sandbox and Harness to report different PID-namespace identities, require a write through /proc/1/root to fail without changing the host target, and preserve child-process management inside the sandbox.

Backend selection matters here. If a host cannot create the required PID namespace, Harness rejects Bubblewrap during its capability probe and falls back to Landlock instead of silently running without confinement. Landlock can still restrict file access, but it does not hide host processes the way the fixed Bubblewrap profile does. A namespace check must therefore be interpreted together with the backend that actually ran the command.

Pin rc.2, then compare namespace identities

For an npx launch, pin the currently published release that contains the fix:

npx @deepseek-ai/[email protected] web

For a source build or internal image, confirm that the build contains commit fe12e047327938012031dc1ec795cbab8afe2cf8. A mutable latest label is not evidence of the code that reached a machine. 0.1.1-rc.2 is still a developer preview, so preserve configuration and regression-test plugins, shell behavior, and file permissions before rollout.

If your team does not want to maintain the Host itself, SandBase Agents now also supports DeepSeek Harness as an Agent runtime engine. The public DeepSeek Harness runtime module shows a pinned DSH headless runtime running inside a separate E2B Sandbox. Keep the two boundaries distinct: --unshare-pid fixes DeepSeek Harness’s built-in Bubblewrap profile, while the hosted SandBase path relies on an outer E2B isolation layer. In either case, record the actual runtime version and sandbox provider instead of writing only “sandbox enabled.”

Then run this command once in the host terminal and once in the Agent’s confined shell:

readlink /proc/self/ns/pid

It only reads the current process’s PID-namespace identifier; it does not write a host file. Under the fixed Bubblewrap profile, the two identifiers should differ.

If they are identical, first confirm whether the command used Bubblewrap, Landlock, or another backend. Do not copy a /proc/1/root host-write test into production just to obtain a dramatic proof. Version, backend, and namespace identity are enough to decide whether the deployment needs an upgrade or a tighter task boundary.

Use the result this way:

  • Still on 0.1.0-rc.8 with Bubblewrap: prioritize an upgrade, then compare the namespace identities again.
  • Build contains the fix but the identifiers match: inspect backend selection; Landlock does not create a private process view.
  • Upgrade is temporarily blocked: do not feed untrusted repositories, issues, or web pages to an Agent that can execute shell commands. Reduce the workspace and available credentials, and run the task inside a disposable outer environment.

The fix is not a complete virtual machine

--unshare-pid fixes Bubblewrap’s process view. It does not add every other boundary an Agent deployment may need.

The Harness sandbox backends discussed here do not restrict network access. Which domains the Agent can reach and whether it can connect to internal services still depend on an outer network policy. The change also does not alter process visibility for Landlock or macOS Seatbelt.

That makes “sandbox enabled” too vague for an operations record. A useful deployment record says which backend was selected, which namespaces are private, where the backend falls back, and which layer controls the network, credentials, and writable paths.

workspace-write is only fulfilled when the backend implementing it isolates the kernel views that could offer a second path around the file policy. The safest check is not whether one direct write failed. It is whether the command can still see the host objects that make an unintended route possible.

Sources