The registry passed notes between sandboxes
Check Point published research on September 8 showing that two ChatGPT code-execution containers, running under two different accounts with no network path between them, could pass data to each other through the internal JFrog Artifactory instance that served them packages. Nothing on the front door broke. The reader credential those containers held could also write, so a metadata field on a stored package worked as a mailbox. Bromure Agentic Coding hands the guest no account on the mirror, and lets you write read-only into a rule the wire enforces.
Isolation held, the connectors behaved as documented, and the service in the middle was installed for security in the first place. The victim's mail still reached a stranger's account, through a metadata field on a stored package.
In June, researchers at Check Point wrote a property onto a file in a package
repository. The property was called chatgpt_test_ts and its value was a
timestamp. They wrote it from inside the sandbox that runs code for a ChatGPT
conversation. Then they opened a conversation under a different account, in its
own container, and read the same property back. The value came through intact.
That timestamp is the whole finding. Check Point published it on September 8 under a title that beats any summary: The Shared Clipboard Inside the Sandbox. OpenAI had retired the service by then. The researchers disclosed in late June and were told the internal Artifactory instance had been decommissioned, so there is no patch to apply and nothing for a user to do. The shape of it stays.
The service in the middle
A ChatGPT conversation that runs code gets its own container, isolated from the
containers of other conversations. That part worked. A container running Python
also needs to pip install, and a careful platform team will not let a sandbox
reach pypi.org on its own. So the sandbox gets a controlled intermediary: an internal
JFrog Artifactory instance that fronts the
public registries and serves vetted packages inward.
This is good design. A bank puts the same thing in front of npm, and a regulated healthcare shop puts it in front of PyPI. The mirror exists to reduce the sandbox's exposure, and it does that.
It also gives each container an account on the mirror.
Artifactory's REST API includes an Item Management group, reachable at
/api/storage/{repoKey}/{itemPath}, that lets a client attach arbitrary named
string properties to a stored item and read them back: Set Item Properties
and Get Storage Item Information. Setting a property requires the Annotate
permission. Reading one does not. Check Point found that the credential issued to
the sandbox containers, meant as a reader, carried both. As
Cybersecurity News summarized it,
"reader credentials handed to the containers had enough permission to both write
and read these properties", and that "those properties were not isolated per
account."
Property values take text, or Base64 for anything binary, and a payload too big for one property splits across several and reassembles on the other side. Two containers belonging to unrelated customers, with no network path between them, now hold a bidirectional channel with no bandwidth ceiling worth mentioning.
Two conversations in the same turn
The attacker's instructions reach the victim by ordinary routes: a pasted prompt, a shared conversation link, or a custom GPT whose builder instructions the user does not see. The victim then sends a normal message, and that is the whole trigger.
In Thinking mode, the model processed two independent streams of work in one turn. Check Point's proof of concept had the victim ask a cooking question and receive a correct answer to it, while alongside that answer the model read the victim's connected Gmail account and wrote what it found into an Artifactory property for the attacker's container to collect. Pedro Drimel Neto, who leads Check Point's malware analyst team, told The Register: "A crafted instruction could make ChatGPT process a second stream of tasks alongside the visible conversation." Gmail was the demonstration. Google Drive, Microsoft Teams and GitHub sat within the same reach.
The victim saw one signal, a small "Talked to Gmail" label, and it appeared after the fact. Connectors default to the Important actions setting, which approves low-risk reads without asking; the stricter Always ask would have produced a prompt. That setting classifies a mail read as low risk without asking who requested it.
Check Point's description of the model: it "can therefore act as a coerced insider: not malicious, but persuaded to act on the attacker's behalf."
The part that generalizes
Strip out ChatGPT and the story is about a coding agent, because the structure is identical.
An agent sandbox has to install packages. Letting it reach the public registries
unmediated is the thing you were avoiding, so you put a mirror in front:
Artifactory, Nexus, a private npm proxy, whatever your organization standardized
on. The sandbox now authenticates to that mirror, so it holds a credential, and
somebody decided what that credential could do long before this agent existed.
Package registries accept uploads, tags, annotations and retention rules, which
makes Annotate a small permission sitting on a wide surface.
Ask two things of your own setup, then, rather than asking whether the sandbox is isolated. Name what it holds an account on. Then name which verbs work on that account.
Inside a Bromure workspace
Bromure Agentic Coding runs each coding agent in a hardware-virtualized Linux VM on your Mac, and keeps the real secrets on the host side of that line. Walk Check Point's three ingredients through a workspace.
A shared service. There is none. Each workspace maps to one VM, with its own system disk, its own home image, its own IP, and its own MITM proxy listener on the host. Two workspaces share no VM, and the manual's description of a pair of them is that they "never share a byte." No fleet-wide mirror sits underneath the workspaces with a metadata plane both can write to. What sits underneath a workspace is a process on your own Mac, one per workspace.
A credential on the mirror. The agent holds none. Package installs in a
Bromure workspace leave over a virtio socket to the host proxy, and the proxy
talks to the registry. Bromure keeps reputation-service API keys host-side and
exports them into no VM. The Depi path is the sharpest case: the proxy attaches
your registry key as an Authorization: Bearer header on the host and strips
whatever Authorization header the guest sent on the way past. No reader
credential exists in the guest, so none can carry a verb too many.
A write verb that outlived its reason. Here you get to write the constraint
down. A workspace's Guardrails pane carries an ordered egress firewall, and rules for the
web protocol take a Methods column. Under allow, the methods form an
allowlist, and read-only is shorthand for GET, HEAD and OPTIONS. The manual says
why the column exists: the method dimension "is what lets a workspace read an
API it is not allowed to write", at the wire, regardless of what tool inside the
VM makes the request. Two layers enforce it. The virtual network switch matches
each flow by destination IP and DNS-snooped hostname, and the proxy matches again
by TLS server name and by individual HTTP method, so a compromised agent has no
route around either. Edits reach running sessions without a reboot, and each
verdict lands as a Firewall row in the Security Timeline.
The second stream, and the way back out
The attacker's second task stream arrived as content the model read. In a Bromure
workspace, whatever an agent ingests and streams back to the model (file contents,
web pages, command output, anything a tool returns) travels as tool_result spans
through the same host proxy. The source-code detector scores those spans with a
local PromptGuard classifier before the model acts on them, then logs the hit,
pauses for your decision, or blocks the request. The detector ships switched off
and pulls a 298 MB model the first time you enable it, so enable it before the
session you need it in.
The unapproved connector read has an inverse here. A Bromure workspace's MCP
bearer tokens appear inside the VM as brm-mcp_ placeholders. The real token
stays out of the guest, and the proxy substitutes it on the wire toward the one
host that token was minted for. Switch on Ask before use for a credential and
its first use in a session pauses for a host-side dialog offering a 5-minute,
1-hour, or rest-of-session grant. That is the prompt "Important actions" declined
to show, per credential, on the machine you are sitting at.
Should something in the VM carry a placeholder somewhere it does not belong, the
proxy refuses the request without forwarding a byte, pauses the VM, and raises an
alert naming the token preview, the credential, the host it was minted for and the
host it was heading to. Under that tripwire, tracing at Activity only writes
one metadata row per request: host, method, path, status, bytes, which credentials
the proxy swapped, and a leak warning for any bearer-style token Bromure did not
mint. Run bromure-cli trace hostnames after a session and each distinct host the
agent contacted prints with a count.
If you run a mirror for your agents
Check the identity your sandboxes authenticate with, ahead of the network path
between them. On Artifactory, look for Annotate on a token you think of as a
reader, and for a permission target broader than the repositories the sandbox
installs from. The property API is one writable metadata plane; retention
rules, tags and build info are others. A reader that can annotate can post.
The rule that answers it in one line
In the workspace's Guardrails pane, add an egress rule for the registry
with the web protocol and read-only in the Methods column, then set
Unmatched traffic to Deny and list what the work needs. The pf-format
disclosure at the bottom of the pane prints what you built:
allow web registry.npmjs.org read-only, allow web api.github.com,
default deny. It applies to running sessions without a restart.
A shared service makes tenants neighbours
The instinct after a story like this one is to check the walls. The walls were fine. Two containers under two accounts had no route to each other, and Check Point found none. They found a third party both containers were entitled to talk to, and used it the way people have used shared drives and DNS TXT records for thirty years.
Check Point states the lesson in the paper: "a shared internal service, meant purely as infrastructure, can become an unintended communication layer across environments that were supposed to remain isolated." Infrastructure you install for security is still infrastructure, and its tenants sit one hop apart. Shrink the set of things a sandbox holds an account on, and move the decision about what those accounts may do onto each request, out of a provisioning ticket somebody closed two years ago.
An agent sandbox worth running will have a controlled path to the packages it needs, because the alternative is worse. Treat that path as a relationship with permissions attached, and treat those permissions as your perimeter. Decide them somewhere you can still see them. Install Bromure Agentic Coding and give your agent nothing to sign in with.