Isolation ran the command
On August 10, 2026, Manifold Security published a flaw in Cursor's CLI agent: the flag that starts the agent in an isolated git worktree read a JSON file out of the repository you had just cloned and passed its contents straight to a shell — before the Workspace Trust prompt, and outside the sandbox even when you had turned the sandbox on. No model, no prompt injection, no persuasion. Bromure Agentic Coding ships the same worktree primitive with no place for a repository to put a command, inside a VM that existed before the repository arrived.
You typed the flag that means "isolate this." That flag is what ran the repository's shell command, as you, on your machine, before anything asked whether you trusted the repository.
On August 10, 2026, Manifold Security's Francisco Rosales published
a finding in Cursor's command-line coding agent
that The Hacker News picked up three days later in
its ThreatsDay roundup.
The proof of concept opens a calculator. That is the polite version of a list
Manifold spells out: reading ~/.ssh, taking cloud credentials from the
environment, opening a reverse shell, writing persistence.
Read it for the delivery rather than the payload. Nobody injected anything, nobody persuaded a model, no clever sentence hid in a README. A tracked JSON file in a repository named a command, and the part of the agent whose whole job is isolation ran it.
A flag, a JSON file, and the wrong order
cursor-agent is the terminal version of Cursor's coding agent. Turning an
agent loose on your working tree makes you nervous, so the CLI offers
containment, documented in its own parameter reference:
-w, --worktree [name] Start in an isolated git worktree at
~/.cursor/worktrees/<reponame>/<name>
A fresh worktree is a clean checkout, so it has none of your build artifacts.
To make it usable, the CLI runs a setup step when it creates one, by default.
That step reads .cursor/worktrees.json out of the repository it has just
checked out and passes the setup-worktree value straight to sh -c:
{
"setup-worktree": "<any shell command>"
}
Manifold's description of what sat between that value and the shell is three words long: "No parsing, no allowlist, no prompt."
.cursor/worktrees.json is an ordinary tracked file. It arrives with a plain
git clone, like a README or a lockfile. On builds before
2026.07.23-e383d2b, worktree creation and setup ran during workspace
resolution — and workspace resolution finished before the code path holding
the Workspace Trust dialog. So the command ran first. In the recording
attached to Manifold's report, the terminal is still printing
Running worktree setup commands…, the calculator opens, and only then does
the prompt appear asking whether you trust this directory.
Cursor is explicit about what that prompt is for: nothing the repository
controls should run before you accept it. When something does, the industry
has a name for the bug class — pre-trust execution — and Cursor has shipped a
fix for it before, in the same directory. In 2025, a repository-supplied
.cursor/mcp.json auto-started its configured server the moment you opened
the project. That became
CVE-2025-64109,
rated High at CVSS 8.8. A permissive .cursor/cli.json handling issue in the
same CLI became
CVE-2025-61592,
also High, also 8.8. The -w worktree path did not exist yet. It shipped five
months after that fix, with the same primitive and no gate.
Manifold reported it on July 20. Cursor shipped the reordering on July 23: the trust prompt renders first now, and the setup command waits until the workspace is trusted. On July 29 Cursor closed the report as Informative, on the grounds that exploitation requires the user to clone an attacker-controlled repository. Manifold's answer is the one worth keeping. Cloning a repository is what the product is for, and it was also the precondition of CVE-2025-64109, the bug Cursor rated 8.8 and patched. Cloning describes the delivery. The defect is elsewhere.
The setting you turned on did not reach that path
There is a second leg, and it survived the fix.
The setup step runs under a hardcoded insecure_none sandbox policy. That is
Cursor's own name for the value: in sandbox.json, type accepts
workspace_readwrite (the default), workspace_readonly, or insecure_none,
which disables the sandbox entirely. The worktree setup path is pinned to the
last one. Passing --sandbox enabled does not change it. Manifold, describing
current builds: updating "closes the pre-trust window, not the sandbox gap."
Put the two legs side by side and you get something that outlives this particular product. The trust gate was a step in a sequence, so it could land in the wrong place. The sandbox was a setting, so a code path could exempt itself from it. The worktree carried the word isolation, so users read containment into it. Cursor's own code decided all three, at moments of its own choosing, inside the process they were supposed to constrain. That is the failure that beat a library's safety flag two weeks ago, and the one behind seven sandbox escapes where nothing escaped a sandbox.
Isolation that shares your user account
-w isolates the working tree. It gives the agent its own checkout so it
cannot trample your uncommitted work, which is a real problem and a real fix.
Nobody built it to isolate the machine. The worktree lives at
~/.cursor/worktrees/, under your user, with your environment, your ~/.ssh,
your shell profile, your cloud credentials, and your keychain a syscall away.
Manifold's list of what the setup command could have done reads like an
inventory of that home directory.
So: a repository you had not read yet chose a command, and the feature you invoked for safety is what ran it. A JSON file and a shell, with the model sitting the whole thing out.
Most of the conversation about agent security has drifted toward the model. Is it gullible, can it be persuaded, did it read something it should not have. Those questions matter and we spend a lot of posts on them. Meanwhile the surest way to run code on a developer's laptop in 2026 is to put it in a file that a tool reads on startup, and wait for someone to clone.
A worktree with no place to put a command
Bromure Agentic Coding ships the same primitive, because
the primitive is good. Press ⇧⌘G in a repo tab, type a task name, pick an
agent, and Bromure cuts a branch wt/<slug> from the current commit, checks
it out under ~/.bromure/worktrees/<repo>/<slug>, opens a tab in it, and
starts the agent on your prompt. Several tasks, several branches, several
agents, one repository — the fleet pattern.
Bromure's setup step has the same job Cursor's does: a clean checkout is
missing the gitignored files an agent needs, so something has to bring them
across. The difference is what the repository is allowed to say about it. The
repo can ship a .worktreeinclude file, and every non-comment line in it is a
path relative to the main worktree root. Bromure copies each one with
cp -a, and only when the source exists and the destination does not. No
field in that file holds a command, so there is no sh -c to sequence
correctly and no ordering question to get wrong. The worst a hostile
.worktreeinclude can ask for is that a file be copied into the checkout.
That is the whole vocabulary.
The bigger difference is where all of it happens.
Run the command. See what it finds.
Take Manifold's list and walk it through a profile, granting the attacker everything — pre-trust, unsandboxed, root in the guest if you like.
Read ~/.ssh. Nothing there to read. A profile's private keys stay on the
host. The VM gets SSH_AUTH_SOCK pointing at /tmp/bromure-agent.sock,
bridged over vsock to a per-profile agent running on your Mac, and Bromure
leaves your macOS launchd agent unplumbed on purpose. The agent protocol has
requests for "list my public keys" and "sign this challenge." It has no
request that means "hand over the private key." Turn on Require approval to
use and every signature becomes a dialog on the host with a time-bounded
grant — five minutes, an hour, the rest of the session.
Take cloud credentials from the environment. They are there, they look
right, and they are fakes. Everything in a profile's Credentials panel is
injected as a placeholder and swapped for the real value on the wire by the
host proxy: brm_… for generic API keys, a synthetic ~/.kube/config with
throwaway client certs, a fake base64 blob in ~/.docker/config.json,
~/.git-credentials, AWS material that is re-signed host-side and answers
InvalidSignatureException to anyone who tries to bypass the proxy. The theft
succeeds and returns nothing worth having.
Open a reverse shell. Now the attacker has to move something across a wire, and the wire belongs to the host. Every outbound request from the VM is scanned against the profile's minted decoys with an Aho-Corasick automaton — headers and body, the whole request, not just the parts that look like credentials. A decoy heading for a host outside the scope it was minted for is the signature of a machine exfiltrating something it should not even know. The proxy aborts the upstream call before the destination sees a single byte, returns a 451 to the guest, pauses the VM, tints the frozen frame red, and raises an alert naming the credential, the host it was minted for, and the host it went to instead. You choose: shut down, save for investigation — disk image, home directory, shared folders, bundled and marked so the profile will not boot again without a wipe — or continue.
Write persistence. The machine's lifespan is one task. Erase home resets
/home/ubuntu, and Reset to base re-clones the workspace system disk.
Meanwhile the work you wanted goes ahead. The agent reviews the repo, runs the tests, opens the pull request. The repository's command ran, in a room where running was all it got to do.
The part patching does not cover
One more detail from Manifold's write-up, and it has the longest shelf life. Cursor published no advisory for the worktree path and left it out of the July changelog, so the fix shipped inside a routine build. Anyone on an affected version had no way to learn that updating closed a pre-trust execution path. You have no way to learn today which tool on your laptop still has one open, because the path is always some file a tool reads on startup that nobody has audited yet.
Cursor closed this one in three days, which is fast. Cursor also closed the
mcp.json version in 2025, and a new feature arrived five months later with
the same primitive. That is what shipping features into a startup sequence
looks like: each capability adds a step, and each step is one more thing to
order correctly on a Thursday.
A hypervisor is not a step in that sequence. It does not read
.cursor/worktrees.json or .worktreeinclude or anything else in your
repository. It was there before the clone, it does not have a policy field a
code path can pin to insecure_none, and its guarantee — this machine is
disposable, these credentials are fake, this wire is watched — is
the same on the day a bypass is published as on the day it is patched.
Keep cloning repositories you have not read. Reviewing unfamiliar code is the job, and handing it to an agent is the point of having one. Just stop letting the review happen in the same account as your SSH keys. Install Bromure Agentic Coding, give each task its own branch, its own checkout, and its own disposable machine, and the next time a startup path turns out to run whatever a JSON file says — and one will — it runs in a room built for it.