Back to all posts
Published on · by Renaud Deraison

The off switch was inside the sandbox

CVE-2026-82533, published September 8, is a 9.4 in DeepSeek Harness: the sandboxed coding agent could switch off its own sandbox with one shell command. The harness ran the agent's commands in an OS sandbox that constrained file writes, and it exposed its control plane as an HTTP interface on loopback, which the sandbox never covered. The check guarding that interface read the Host header the caller supplied and never looked at where the connection came from. In Bromure Agentic Coding the agent is already unconfined inside the VM, and the control plane it would have to call does not exist on its side of the line.

This one took no exploit. The confined agent ran a shell command against a local port, asked the sandbox holding it to switch itself off, and the sandbox agreed.

DeepSeek Harness runs a coding agent's commands inside an operating-system sandbox. The sandbox is narrow and deliberate: file writes stay inside the workspace and the temporary folders, and everything else the agent does is someone else's problem. The project's own command-line reference says as much. Under default settings, "reads and network access are not confined."

The harness also has a web interface. It runs on the same machine, on a local HTTP port, and the harness hands its address to the agent's shell so tools can talk to it. That interface is the control plane: it holds a session's mode, including the mode called danger-full-access, which turns off the sandbox and stops the approval prompts.

Both of those designs are ordinary. Put them next to each other and the agent can switch off its own sandbox with one command, because the sandbox never covered loopback and the control plane never checked who was calling.

Researchers at OX found it. VulnCheck published it on September 8 as CVE-2026-82533, CVSS 9.4. It worked on a default install, with no network exposure and no credentials, until DeepSeek shipped a fix on August 27.

The check that read the envelope

The interface had no authentication at all. What stood in for it was a function named isTrustedApiRequest, and DevOps.com quotes what it did: it "read the 'Host' request header and allowed access if the value was a loopback authority or appeared in a configured 'trustedHosts' list."

The Host header is a line of text the client writes. It says what address the client believes it is talking to, and a caller anywhere on the network can type localhost into it. The connection's real origin sits a layer down, in the TCP peer address, and DeepSeek's check never read that value. The CVE record files the bug under CWE-345, Reliance on Untrusted Inputs in a Security Decision.

The agent, sitting inside a sandbox that permitted network calls, made one to the interface and set its own session to danger-full-access with approval set to never. As The Hacker News put it, the mode change "did not require explicit approval because it modified session settings rather than requesting new permissions."

The approval system worked as designed. The agent never asked to do something dangerous; it asked to change a setting, and that setting governed whether dangerous things get asked about at all. A permission gate inspects the operation in front of it. This request was a configuration write, and configuration writes were not on its list.

one machine, one process, two decisions that never metOS sandbox: what it constrainsthe coding agent’s shell commandsfile writes → workspace + temp onlyenforced by the operating system, and it heldout of scope, by designreads: unconfinednetwork: unconfined, loopback includedPOST http://127.0.0.1:…Host: localhostharness control plane: local HTTP, no authisTrustedApiRequest(req)• reads the caller’s Host header• loopback authority or in trustedHosts → allow• never reads the TCP peer addressthe resulting session statemode = danger-full-accessapproval = nevera settings write, so nothing prompts
The escape, in full. The OS sandbox constrains file writes to the workspace and temp folders; reads and network calls, including loopback, sit outside its scope by design. The harness's control plane listens on a local HTTP port whose address the agent's shell already knows. Its trust check reads the caller's own Host header and never inspects the TCP peer address, so a request from the sandboxed process looks the same as one the developer made. The agent then writes its session mode to danger-full-access and its approval setting to never. That is a settings write rather than a permission request, so nothing prompts.

The same door, facing the other way

An interface that trusts a header the caller supplies does not care which direction the connection arrives from. If the port was reachable over a network, the same call worked from off the machine: an unauthenticated stranger could take control of the agent and export every stored conversation, with no API key and without spending a token on a model call. That is why the CVSS 4.0 vector opens with AV:N, and why the number is 9.4 rather than something local and mild.

The timeline has a detail worth keeping. Two developers posted the finding on DeepSeek's GitHub discussion board on August 13 and 14, on their own, before OX confirmed it on August 24 and before a CVE existed. The repository had more than 216,000 stars on September 9 and no security policy file describing how to report a vulnerability in private, so the only place left to put it was a public thread. The fix, when it came, was authentication: the tool now prints a one-time token at its startup address, the browser exchanges that token for a signed cookie, and every call to the interface requires the cookie.

If you run this harness, check the version on your machine rather than the version the project ships. Third-party desktop wrappers bundle their own copy. 0.1.2-alpha.1 was GitHub-only on August 27, 0.1.2-alpha.2 on August 30 was the first npm release carrying the fix, and one Windows wrapper sat on 0.1.1-rc.2 until it moved to a patched build on September 6.

Your harness has one of these too

You could file this under one project's bug and move on. The shape travels, because agent harnesses are sprouting local control planes: a status server for the dashboard, an IDE bridge, an MCP endpoint, a page on localhost that renders the diff. Each is a small HTTP service on your machine, and the code your agent runs can reach all of them, because the agent runs on that machine and localhost is what "that machine" means.

Once a control plane sits next to the thing it controls, one question governs the outcome: can the confined party address the confinement's settings? DeepSeek answered yes, through a check that took the caller's word for it. A stronger check still answers a question that should never have been askable. An authentication function is code, code has fallback branches, and this year has been a long parade of security decisions failing in the branch no one exercised.

Where the switch lives in a Bromure workspace

Bromure Agentic Coding starts from the other end. A Bromure workspace leaves the agent unconfined.

Inside the guest the agent already has what DeepSeek Harness would call danger-full-access. That is the resting state, by design. The manual says as much: a prompt-injected or otherwise misbehaving agent "can do anything it likes inside the guest, but it cannot read a real API key, sign with a real AWS secret, or extract an SSH private key — none of those exist on its side of the line." The agent can write anywhere in the filesystem, run what it wants and bind any port it likes, so it has no mode left to escalate to. The boundary is a hypervisor edge with the agent on the far side of it.

The guest therefore has no address for the control plane at all. The workspace's policy (guardrails, credentials, firewall rules, MCP servers) lives in a profile.json under ~/Library/Application Support/BromureAC/profiles/ on your Mac, and you change it in the Edit workspace window. The guest has no filesystem path to that file and no network route to the process that reads it.

The two sides talk over virtio sockets, point-to-point host-to-guest bridges that run outside the VM's network. A workspace VM has eight, each with a job: 8443 carries the guest's HTTPS to the host proxy, 8444 is the ssh-agent bridge, 8445 feeds the AWS credential helper, 5800 is the terminal and file path, 5010 relays OAuth callbacks. Each one serves a fixed protocol and none of them takes a Host header, so a caller has no trustedHosts list to talk its way into. Identity on a vsock is topology: which bridge the bytes arrived on. You cannot type that into a request.

the harness: sandbox and its settings, same machinesandboxed agentfile writes constrainednetwork unconfinedknows the interface addressloopback HTTPguarded by a header the caller writescontrol planesession modeapproval settingone request away from the thing it governsa Bromure workspace: everything inside, policy on the other sideworkspace VMthe agent has full access herewrite anywhere · run anything · bind any portno mode to escalate tolocal control planes it starts listenon this VM’s loopback, not your Mac’sno real credentials exist on this sidehypervisorvsock 8443HTTPS onlyno control pathmacOS hostper-workspace proxy: the wire boundaryguardrails · egress firewall · fake credentials swapped:80 and :443 diverted by the virtual switchnothing the guest can unsetwhere the policy is stored~/Library/Application Support/BromureAC/…consent dialogs render here, in AppKit
Two placements of the same switch. Above: the harness's sandbox and the control plane that governs it run on one machine, so the agent reaches the settings over loopback and the only thing standing between them is a check on a header the agent writes. Below: a Bromure workspace grants the agent everything inside the guest and puts the policy on the other side of the hypervisor. The virtual switch diverts the guest's outbound HTTPS into the host proxy, with no environment variable to unset; guardrails, the egress firewall and the credential swap all run there; and approval dialogs render on macOS. The guest has no address for any of it.

Approvals that cannot be set to never

The second half of danger-full-access turned off the prompts, and that half deserves its own answer. An agent that silences its own approvals is the part that would keep me up.

In a Bromure workspace the prompts live on the host. The proxy raises them after the request has already left the VM, so the session inside the guest carries no setting that could suppress one. Ask before use pauses the first use of a credential in a session and offers time-bounded grants: five minutes, an hour, the rest of the session, or Don't allow. A write policy set to Prompt before write stops each mutation with a dialog headed Allow write on "<scope>" from workspace "<name>"? showing the literal operation, the SQL statement itself or METHOD /path for a REST call. Allow once creates no grant at all, so the next write prompts again. Grants live in memory and vanish when the session window closes.

The guardrails page states the property in one clause: a write policy is "enforced in the proxy, so a compromised agent in the VM can't bypass it." The egress firewall underneath it works the same way, an ordered rule table with an Unmatched traffic control you can set to Deny, applied twice: once at the virtual switch by destination IP and DNS-snooped hostname, once at the proxy by TLS server name and, for web rules, by HTTP method. Rule edits reach running sessions without a reboot.

An unattended run fails the safe way. A workspace driven headless over SSH or an automation gets the same four choices as a text prompt inside its tmux, and no answer means deny. The worst outcome there is a blocked call and a red row in the Security Timeline. In this CVE, the agent set approvals to never and the prompts went away.

If you run an agent harness on your Mac

Ask what its local interfaces are and who can call them. Inside a Bromure workspace, bromure-cli vm ports <workspace> prints the guest's live listening sockets, with port, protocol, address and process, and loopback-only binds marked. The VM dashboard's Listening Ports card shows the same. That inventory is the question this CVE turned on, and one command answers it.

If the interface faces outward too

The remote half of CVE-2026-82533 needed the port to be reachable. Workspace VMs run on a private NAT network: they are reachable from your Mac, but they are "not exposed on your physical LAN, and inbound connections from elsewhere are not possible unless you explicitly publish a service." An unauthenticated agent-control port that a coffee-shop network cannot route to leaves you a patch to apply on your own schedule.

Confinement you can revoke is a preference

DeepSeek shipped a weak check and fixed it three days after OX confirmed it. The lasting part is what the check was guarding. A boundary drawn around a process by that process's own runtime is a boundary the process can negotiate with: it has an address, an API, and a settings object with a field in it. Somewhere behind that field runs a code path deciding whether this caller may write it, and a code path of that kind is one bad default away from decoration.

Draw the boundary under the process and there is no counterparty to negotiate with. The agent in a Bromure workspace holds root, holds the whole filesystem and can start any service it likes on any port. Its API keys are decoys, its only route to the network is a virtio socket to a proxy on your Mac, and the file holding its permissions sits somewhere it cannot read. Hand the agent everything on its side of the line and you stop having to defend the line.

Coding agents will keep growing local control planes, because a control plane is how you build a dashboard, an IDE bridge or a diff viewer. Each project then has to answer whether the code its agent runs sits on the same side of the line as the settings governing that agent. Get that wrong and authentication is the only thing still holding, which is how a 9.4 comes down to one shell command. Install Bromure Agentic Coding and put the switch somewhere your agent cannot reach it.