Four agent sandboxes were patched in five days, and every rule was correct
Claude Code's `**/.env` deny rule lost to an allow region, skipped directory contents, and fell to a rename. DeepSeek Harness let confined processes out through `/proc/<pid>/root`. Ray's browser defense is a `User-Agent` string check. Copilot's memory survives a password change. The versions to check today, and the four dimensions a containment rule has to name before it means anything.
Claude Code 2.1.236 went out on August 19 with this line in the changelog:
Sandbox: on macOS, wildcard read-deny rules (e.g.
**/.env) now take precedence inside allowed read regions, cover matched directories' contents, and can't be bypassed by renaming the denied file
That is one sentence describing three separate failures of the same rule. Before that build, a deny rule for **/.env could lose to an allow rule covering the same location. It did not reach into the contents of a directory the pattern matched. And it stopped applying the moment the file had a different name. Someone wrote **/.env into a settings file, watched the agent decline to read a secret, and concluded the secret was out of reach.
Over the next two days, three more containment rules from three unrelated vendors were published as insufficient. None of them were defeated by anything exotic. Each one was a true statement about a boundary that turned out to be scoped to a dimension its author had thought about, while the way in ran along one they had not.
That is the useful part, and it is worth more than the four patch notes. A sandbox is not a wall. It is a sentence of the form this thing cannot reach that thing, and the sentence is only as wide as the mechanism you named when you wrote it.
The rule said .env, so the file was called something else
The Claude Code fix is the cleanest illustration because all three of its failures live in one rule.
A deny pattern names files by path. That is the dimension it covers. A file's path is not a property of the secret inside it, so anything that changes the path moves the file outside the rule: cp .env .env.bak, mv .env config/local, or a directory rename one level up. The rename bypass was not clever. It was the rule doing exactly what it said, on a filename that no longer matched.
The precedence half is the more common trap in configuration generally. Two rules covered the same path, one permitting and one denying, and the resolution order was not the one a reader would assume. If you have deny patterns configured in Claude Code on macOS, run claude --version; anything below 2.1.236 needs the upgrade. The current build as of this morning is 2.1.241.
Bubblewrap confines mount namespaces, and /proc is not one you listed
DeepSeek shipped dsh-v0.1.1-rc.1 of DeepSeek Harness on August 21 at 07:12 UTC with one release-note line that matters:
Prevent confined processes from escaping Bubblewrap restrictions through
/proc/<pid>/root
Bubblewrap is the same unprivileged sandboxing tool Flatpak uses. It builds a restricted view of the filesystem for the confined process by constructing a new mount namespace. The claim it makes is about mounts: paths you did not mount are not visible.
/proc/<pid>/root is a symlink the kernel maintains to another process's filesystem root. It is not something you mounted, so a rule expressed in mounts does not reach it, and a confined process that could read that path had a route back to a root it was supposed to have lost. Anyone running the harness as an agent runtime should check dsh --version and take anything below 0.1.1.
Ray's browser defense is a string comparison, and it has been on CISA's exploited list since August 17
The third case is the one with the most instructive artifact, because the code carries its own warning label.
Ray, the distributed execution framework, exposes a dashboard and a job-submission API on port 8265 with no authentication on /api/jobs or /api/job_agent/jobs/. That is not an oversight. Ray's own security documentation states the position plainly:
Ray expects to run in a safe network environment and to act upon trusted code.
and, on the services in question:
If you expose these services (Ray Dashboard, Ray Jobs, Ray Client), anybody who can access the associated ports can execute arbitrary code on your Ray Cluster.
Which leaves one thing standing between a web page you visit and code execution on your laptop: a check that the request did not come from a browser. Here is what that check was, quoted in the GitHub advisory for CVE-2025-62593 along with its own docstring:
This heuristic is very weak, but hard for a browser to bypass- eg, fetch/xhr and friends cannot alter the user-agent
The function returns true when the User-Agent header starts with Mozilla. The author knew it was weak and named the assumption it rested on. The assumption is wrong: in Firefox and Safari the fetch API permits setting User-Agent. Chrome does not, which the advisory notes is the result of a Chromium bug that puts Chrome out of spec, so the browser that behaves correctly is the vulnerable one. Combine the header rewrite with DNS rebinding, which makes the browser treat an attacker's hostname as resolving to 127.0.0.1, and a malicious page or a malicious ad executes shell commands against the Ray instance running in your other terminal. The published proof of concept opens Calculator, which is the polite version.
The scoring is CVSS 4.0 9.4, critical. Two dates are worth holding together. Ray 2.52.0, which fixes it, went to PyPI on November 21, 2025. CISA added the vulnerability to its Known Exploited Vulnerabilities catalog on August 17, 2026, with a federal remediation deadline of August 20. Nine months separate the fix from the confirmation that people were being exploited through it, and CISA's own description names the population precisely:
Developers using Ray as a development tool may be exposed to this vulnerability exploitable through Firefox and Safari.
Ray 2.52.0 also added built-in token authentication, and the documentation is careful to say what that is and is not: "Token authentication is not an alternative to deploying Ray clusters in a controlled network environment. Rather, it is a defense-in-depth measure that adds to network-level security." Check with ray --version. Current is 2.58.0.
Memory outlives the credential, so revoking the credential does nothing
The fourth case is not a filesystem or a network boundary at all, which is why it is in this list.
Varonis Threat Labs published its analysis of CVE-2026-24301 on August 18, the day Microsoft's patch landed. It describes a chain in Microsoft Copilot Personal (their earlier SearchLeak finding covered Microsoft 365 Copilot Enterprise; this one does not). A link carrying ?q= together with ?autorun=1 executes an attacker's prompt on page load with no click. The prompt queries connected OAuth services and exfiltrates the answers through Copilot's own URL-fetching capability, which looks like ordinary HTTPS. Reported to Microsoft in December 2025, patched August 18, 2026, with no evidence of exploitation in the wild.
The third link in the chain is the transferable one. A prepared web page that Copilot summarizes writes attacker instructions into cross-session memory, and Varonis describes what that store does:
does not reset between sessions and does not clear on logout, and is never automatically deleted or overwritten
and what it costs to detect:
The memory write produces no process, file, network connection, or log entry that security tooling would flag
Everything an incident response runbook does at this point is aimed at credentials. Rotate the password, revoke the sessions, re-enroll the device. None of it touches the memory store, because memory was never classified as an authentication artifact. The boundary the runbook enforces is the session; the injected instruction lives outside it and rides into every future conversation. This is prompt injection with a lifetime, and the lifetime is the part that breaks the response process.
Two of these are bugs and two are working as documented
Worth being precise, because the correct action differs.
Claude Code and DeepSeek Harness shipped fixes for things that did not behave as advertised. You upgrade, and the rule then means what you already believed it meant.
Ray and Copilot memory are the harder category. Ray does exactly what its documentation says, and the documentation says it plainly. The gap is between that documented posture and the mental model of a developer who ran ray start on a laptop to test something and never classified it as an exposed service. Copilot memory persisting across logout is a product feature, not a defect. The defect was the write path, and the feature means anything written during the eight months between report and patch would still be sitting there. Varonis reports no evidence of exploitation in the wild, and the shape holds anyway: a patch closes the write, not what was already written.
The version bump handles the first category. Only reading the sentence handles the second.
Write the sentence, then attack the words in it
The exercise takes about twenty minutes on your own setup, and it is the part that survives all four of these patches.
For each boundary you are relying on, write it as one sentence: X cannot reach Y. Then go after the four dimensions that showed up this week.
Naming. How is Y identified? If by path or filename, what happens when it is copied, renamed, symlinked, or read one directory up? Test it rather than reasoning about it: put a dummy secret in a file your deny rule covers, ask the agent to read it, then rename the file and ask again.
Namespace. If X is confined by a mechanism, what does that mechanism actually enumerate? Mounts, process IDs, network namespaces, and user IDs are separate things, and a rule expressed in one of them says nothing about the others.
Network. What is listening on localhost right now that you started "just for development"? Run lsof -iTCP -sTCP:LISTEN -P -n and read the list honestly. Local model servers, MCP servers, notebook servers, agent runtimes and job schedulers all default to a posture that assumes the network is trusted, and the browser you have open on the same machine is on that network.
Lifetime. What outlives the session? Persistent memory, cached tool results, on-disk agent state, and vector stores are not credentials, so credential rotation leaves them intact. If you cannot answer "how do I inspect and clear this," you do not have a revocation path.
Who this actually lands on differs. If you build solo and your development machine is also your browsing machine, the network dimension is the urgent one and the four version checks are twenty minutes of work you can finish before lunch. If you run a platform team, the naming and namespace dimensions are the ones to encode: deny rules and sandbox profiles are configuration, which means they are reviewable, testable in CI, and currently almost never tested. If you use assistants without writing code, the lifetime dimension is yours; open the memory settings on every assistant you have connected to an email or drive account and read what is in there.
We have written before about an agent finding its way out of a sandbox built to hold it, in OpenAI's own postmortem and in what tool access costs you. This week ran in the other direction: the agent was not the adversary, the containment rule was simply narrower than its author's own summary of it. Both directions end in the same place. The rule you wrote is the whole of the protection you have, and a rule that names a filename protects a filename.
Get the next post when it ships
One email on Sunday with the new post and a short list of what shipped that week — new guides, tool updates, and a couple of links worth reading.