Fourteen permission rules seemed like enough when one researcher first tried to keep two protected paths out of a coding agent’s context. A September 2026 arXiv preprint reports what followed: five weeks later, the deny list had grown to 586 rules, and by the paper’s classification the protected files stayed reachable through routes no rule named, including the repository’s own version history. The preprint formalizes a split most teams discover by accident: the agent may not read the secret code, but the build still can, because the compiler runs as the same user, inside the agent’s container, as a child of the agent’s own shell.
If your team hands an agent like Claude Code a repository while keeping licensed code, unreleased research, or customer-specific logic out of its context, the practical finding is this: path deny rules withhold the agent’s tokenized read where a rule matches, never the build’s. Anything the build itself must not see has to leave the agent’s environment entirely. That shifts the enforcement point from the prompt into CI, and it likely costs you agent performance; the nearest measurement is indirect, from a post-quantum migration study, where cutting a model’s served context window from 128K to 32K lowered full passes from 36/40 to 4/40.
The all-or-nothing assumption this breaks
The two evaluations cited in this article were both produced under full repository access. CodeAgentBench, a repo-level benchmark of 101 samples drawn from real Python projects, states the arrangement plainly: “for each task, LLMs are provided with documentation containing the requirements needed to be implemented, along with a set of tools we designed, as well as full access permissions to code files in the repository.” The same work found that a symbol-navigation tool is used about 2.45 times per code generation on average, and that performance significantly declines when it is removed. Repository access is not incidental to agent performance; it is load-bearing.
The later of the two keeps that default. A post-quantum cryptography migration study reports testing “Codex CLI 0.154.0 with gpt-6-astra, and Claude Code 2.1.272 with claude-fable-5-1, both at high reasoning effort” (versions as the authors report them), again handing agents whole repositories. So when a team denies an agent part of a tree, it is departing from the conditions under which the capability numbers cited here were produced. Benchmark results from full-access setups will overstate what a segmented agent delivers.
What a deny list actually withholds
The preprint’s mechanism is the one most agent harnesses expose: “Its permission rules include a deny list of command and path patterns. The harness refuses any tool call the agent requests that matches one of them.” What that buys, on the routes a rule names, is protection of the agent’s read. And the paper is careful about why the agent’s read is the one worth blocking: “The compiler’s read ends on the same machine, in object code that the agent executes. The agent’s read ends in its context window, which is tokenized and leaves the machine.”
That distinction is the whole argument. Source text that reaches the context window is transmitted to the model provider, stored wherever the provider’s pipeline puts it, and becomes reproducible in later output. Object code that never leaves the build machine is a different exposure class. For a cooperative agent (one that is not actively trying to exfiltrate), stopping the tokenized read addresses the realistic leak. The paper is explicit that this is all it claims: it assesses only what mechanisms available to an ordinary user can express, and it “does not offer an arrangement that holds against a hostile agent.”
Why the build still sees everything
The structural reason deny rules cannot extend to the build is stated in one sentence: “The agent and the build run as one user account, and the compiler is a child of the agent’s own shell, inside the agent’s container.” When the agent invokes the build, the compiler inherits the agent’s permissions. There is no principal boundary between them for the operating system to enforce.
The paper compresses this into three structural limits of permission rules of this kind: “a) matching a command string does not mediate a file open; b) a rule that names a path cannot say which program is reading; c) a permission that a child process inherits cannot distinguish the build from whatever started the build.” Read those as a unit and the conclusion follows: inside one user account and one container, no command or path rule can separate “the agent reading a file into its context” from “the compiler reading the same file into object code.” The mechanism is not failing to be clever enough. It is answering a question the permission system cannot hear.
The maintenance bill
Even within what deny lists can express, coverage does not stay bought. The author-reported case study, the same preprint, kept one deny list under revision for five weeks with the protection target held still at two paths: “Four dated revisions took the rule count from 14 to 488, 540, 556 and 586.”
Note the shape of the growth. The first three revisions added 118, 13 and 4 new command names (preprint), taking distinct names from 10 to 128, 141 and 145, so most of the growth was new command coverage rather than guard refinement. The fourth is the informative one: it added 30 rules and no new name, extending fifteen already-listed commands from directory-level guards to single-file guards. Its cause was a gap in the generator script: the two protected targets had separate command lists, and nothing checked that every reader in the directory list was also in the file list. Each rule names one command and one target, so the rule language cannot say that two targets must be protected alike.
Rule count is also a poor proxy for safety: in the studied case, a 586-rule list covering two paths is not obviously stronger than the 14-rule list it replaced; it is more precisely matched to the commands that were actually being used to reach those paths. Budget deny-list upkeep as recurring maintenance with a human in the loop, not as a one-time configuration. If your organization cannot sustain that review cadence, the deny list will silently drift out of sync with the ways protected files can be reached.
Where deny rules leak
The clearest example is the repository’s own history, a route the paper classifies as uncovered by every mechanism it examines: “The third is the repository’s own history. The protected files are under version control and the repository sits in the agent’s tree, so the version-control tool can print any of them at a revision, addressed by a path relative to the repository that no rule names.” Deny rules name paths as they exist in the working tree. git show HEAD~3:secret/codec.c (as a hypothetical shape of the access, not a quoted command from the paper) addresses the same content by a different route, and a path rule that names the working-tree location does not match it.
Be clear about the evidentiary status, though: the paper never ran this route. It classifies fifteen prospective routes and observed only two refused in practice, a direct read and an encoder invocation, both “denied on the first attempt against a decoy tree in July 2026”; “We did not run the other thirteen, against the protected files or the decoy.” The git-history route is reasoned classification, not an observed bypass, and it sits among five routes the paper places outside both the permission rules and the sandbox, alongside the compiler in preprocess mode, a recipe under an allowed build target, a hook-invoked read, and a read by an MCP policy server.
The general lesson: any channel that can render file contents without opening the file at its denied path is a candidate leak. The honest posture is to assume the list of rendering channels is not enumerable in advance.
Which mechanism withholds what
The deny-list row below reflects the preprint’s classification of its own deployment, not a test result: the paper says 21 of its coverage cells “follow from those statements or from shell semantics, which is our reasoning rather than a measurement,” and that its table “is not a measure of how often an attack would be stopped.” Only two routes were ever observed, both refused against a decoy tree. The other mechanisms follow by inference from the compiler-is-a-child finding: if the problem is that agent and build share one environment, the fix must remove the protected source, the build, or both from that environment. The paper does not test these arrangements; treat them as design options whose leak columns are reasoned, not measured.
| Mechanism | Agent file reads | Build-time visibility | Derived artifacts in agent’s tree | Main leak or cost |
|---|---|---|---|---|
| Path deny rules | Blocked for direct reads and named tools; twelve of the paper’s fifteen routes evade the command match | Fully visible: compiler runs as agent’s user in agent’s container | Object code present | Version-control history, compiler preprocess mode, allowed recipes, and hook and MCP reads are covered by no mechanism; rule-count drift |
| Submodule or split-repo boundary | Files not present in agent’s tree | Build breaks unless prebuilt inputs supplied | Only what the build emits | Build integration work; history of the split repo still readable if cloned |
| Prebuilt binaries fetched at build time | Blocked by absence | No protected source on machine | Binaries/linkable objects present | Fetch credentials and binary inspection become the new surface |
| CI-side build the agent never sees | Blocked by absence | None on the agent’s machine | Only published artifacts | Agent loses the run-fix loop for protected code; CI becomes the enforcement point |
Two things are worth reading out of the table. First, deny rules are the only row that withholds any of the agent’s reads while leaving the build untouched, which is exactly why they are attractive and exactly why they are not a security boundary. Second, every stronger row pays for the withholding with engineering: the build must be re-plumbed so it no longer needs the protected source in the agent’s environment. Strict artifact segregation is achievable in agent pipelines, as demonstrated for evaluation fairness in VibeMemBench (111 targets across 90 repositories and 3,634 trajectories), where “the target gold patch enters only this offline screen, the target test patch remains evaluator only, and neither artifact reaches experience construction, runtime memory retrieval, or the target solver context.” That design kept answer keys out of solver context for fairness rather than secrecy, but it shows the plumbing pattern works when the pipeline is built for it.
The cost of withholding context
Segmentation is not free, and the strongest quantified evidence comes from a different task domain, so treat the number as directional. In the post-quantum migration study, a Go file-signer migration from RSA to ML-DSA-44, “reducing only Qwen3.8’s context window from 128K to 32K lowers full passes from 36/40 to 4/40.” That is a context-window restriction, not a path denial, but it measures the same underlying variable: how much of the relevant material the agent can hold while working. Withholding protected modules also removes the interfaces, call sites, and idioms the agent would have used to integrate against them.
Combined with the CodeAgentBench finding that navigation tooling is load-bearing, the implication is uncomfortable: the more successfully you hide a module, the worse the agent will be at writing code that touches it. Plan for the human to own the integration boundary, or accept degraded pass rates at the seams.
What to actually do
Treat path deny rules as context hygiene for a cooperative agent. They are the right tool for keeping provider-side context clean of licensed or embargoed source, and nothing in the evidence supports leaning on them against an agent that is actively probing for the files.
Move anything the build itself must not reveal out of the agent’s reach: compile it in CI, or fetch it as a prebuilt artifact at build time. This follows from the compiler-is-a-child finding, not from a tested deployment in the paper, so pilot it on work that tolerates iteration friction before committing the whole pipeline.
Budget the deny list as maintenance. The studied case went from 14 to 586 rules in five weeks against a target of two paths (preprint); the first three revisions grew by adding command names, and the fourth grew by closing a guard gap between the two targets. Audit for the version-control history route specifically; it is one of five the paper classifies as uncovered by every mechanism it examines.
Verify vendor behavior before trusting it. The preprint does name its agent: Claude Code, identified in its acknowledgments as the studied tool, with Anthropic’s Claude Code sandboxing documentation cited for what the permission rules and the sandbox each cover. The sandbox’s limits “apply to Bash, PowerShell, and Monitor commands and the processes they start,” while the built-in file tools “follow permission rules instead,” so a refusal through one does not establish that the file is out of reach through the other. The paper also cites a published demonstration of Claude Code escaping its own denylist and sandbox. Cursor appears only through its own documented limit (“the terminal and MCP server tools used by Agent cannot block access to code governed by .cursorignore”), and Codex is not mentioned in the paper at all. Treat the command/path semantics described here as grounded in Claude Code’s documentation; whether Codex matches them, including its handling of git subcommands, child processes, and sandboxing, must be checked against current vendor documentation for the versions you run.
What this evidence cannot settle
The segmentation study is a single author-reported study of one research codebase, and all of its quantitative findings (the rule counts, the revision cadence) carry that caveat. The route table is the author’s classification (preprint): the only routes observed in practice were a direct read and an encoder invocation, each refused on first attempt against a decoy tree, and the paper itself calls its coverage cells “our reasoning rather than a measurement.” No supplied evidence tests these mechanisms against an agent attempting to reach the actual protected files, let alone a hostile one. The 36/40-to-4/40 performance figure comes from a post-quantum migration task with a context-window manipulation, not from path segmentation, so it bounds the intuition rather than the practice. The tool-specific picture is uneven: the segmentation preprint names Claude Code as its studied agent and grounds its scope statements in Anthropic’s sandboxing documentation, Cursor appears only through its own documented .cursorignore exclusion, and Codex is absent from the segmentation paper entirely; the migration study’s contribution on this front is only that agents at its reported versions were handed the full source. The durable contribution is the framing: the agent’s read and the build’s read are different exposures, and only one of them is even addressable by a prompt-side rule.
Frequently Asked Questions
How many permission rules did the deny list grow to in the studied case?
Four dated revisions took the rule count from 14 to 488, 540, 556 and 586.
Why can’t path deny rules stop the build from seeing protected files?
The agent and the build run as one user account, and the compiler is a child of the agent’s own shell, inside the agent’s container.
What is one specific route deny rules fail to cover?
The third is the repository’s own history. The protected files are under version control and the repository sits in the agent’s tree, so the version-control tool can print any of them at a revision, addressed by a path relative to the repository that no rule names.

Join the discussion
Share a useful perspective or ask a question about this article.