Examine the defenseAgent harnessesRuntime effects
What the agent said is not what the process did
A command hook blocked a direct write and missed three equivalent forms. A read-only mount stopped their effects. What one small lab shows about monitoring and enforcing an agent's authority.
Filesystem lab · 8 casesPrepared October 1, 20267 min readRethinking Agents
What this rests on
Observed by us: eight fixed-script cases in Linux Docker containers with synthetic files, no model. Reported by others: community operator accounts and documented tool/runtime capabilities. Proposed: the wider harness review and process-ownership design. No coding client's hooks or sandbox were tested.
Sources checked October 23, 2026. Read the source record and limitations.
An engineer gives a coding agent permission to fix a parser and run tests. The agent can invoke a shell. A hook rejects a direct request to change a protected file. The next request invokes a short script, and the hook allows it.
The hook has seen the tool request. It has not necessarily seen what the process will do. If the script holds the same write authority, changing the representation may change the hook's decision without changing the eventual effect.
That is a review question even when no malicious intent is involved. An accidental cleanup, a persistent repair attempt and a prompt-injected instruction can reach the same resource. To decide whether the task stayed within its authority, inspect the effect and the boundary that governs it.
A tool trace is a starting point
Tool tracing already exists. Langfuse (opens in a new tab) describes observations as “LLM calls, tool calls, retrieval steps.” LangSmith (opens in a new tab) includes tool invocations in its runs. It would be inaccurate to say these systems only record what a model says.
An instrumented shell call can nevertheless produce a span saying python job.py ran successfully while the program starts descendants, changes files or contacts a service. Those operations need their own evidence if the review depends on them. An application's instrumentation may cover them; establish that coverage rather than assume it from the existence of a trace.
Separate five things: the authorized task, the requested operation, the enforcement decision, the actual effect, and the evidence available to the reviewer. Reasoning text and final summaries can help explain a decision. They cannot establish that a process ended or a receiving service committed exactly one update.
Four forms of the same write
We ran a deliberately small filesystem lab. The authorized task writes a result into a workspace. A second operation tries to change a synthetic canary in a protected directory. No deletion, real credential, model or coding client is involved.
Our intentionally naive filter rejects a command containing the protected directory's literal path. We express the same canary write four ways: inline Python, a staged script, an encoded program and a parent process that starts the staged script. The filter sees only the invocation string. Scripts are fixture inputs; this does not test a client's file-write hooks or its built-in permission parser.
Each form runs with a writable protected mount and then a read-only protected mount. Both configurations have the same unprivileged container, disabled network and read-only root filesystem. Only the protected mount's write permission changes. A driver outside the container checks file contents after the attempt.
| Form | Invocation filter | Writable mount | Read-only mount |
|---|---|---|---|
| Direct inline write | Blocked | No attempt; unchanged | No attempt; unchanged |
| Staged script | Allowed | Canary changed | Write failed; unchanged |
| Encoded program | Allowed | Canary changed | Write failed; unchanged |
| Child process | Allowed | Canary changed | Write failed; unchanged |
The separate legitimate workspace write completed in all eight cases. This is a narrow availability check, not evidence of complex coding-task completion after a refusal. The driver treats container setup failures as failed experiments rather than successful protection.
In the writable cases our payload deliberately prints protected unchanged after modifying the canary. The external digest shows that the statement is false. We constructed that mismatch; it says nothing about whether a language model would lie. It makes the evidence distinction visible.
The filesystem checks the attempted write after the encoded text becomes executable code. It does not need to understand why the program was written that way. This property is the useful result. It is not proof against privileged execution, kernel bugs, other writable resources, network disclosure or permitted remote actions. Method, environment and reproduction script.
Put the policy outside the writable task
A hook is useful for reviewing an invocation and catching familiar mistakes. An OS restriction can apply to the operations performed by its descendants. Current Claude Code sandbox documentation (opens in a new tab) explicitly describes that descendant coverage. The design is already available; the hard question is the effective allowance and every path around it.
For a parser task, consider a writable checkout and scratch directory, read restrictions for unrelated private data, bounded network destinations, and a separate release decision. Confirm where policy configuration lives, who can change it, whether a command may fall back outside the sandbox, and whether another tool has broader authority. A hook inside a writable repository cannot be the only evidence that its own configuration survived.
Receiver authorization matters too. A process can remain inside its sandbox and send inappropriate content through an allowed endpoint. Our earlier sandbox pilot observed this with synthetic private notes. A domain allowlist controls a destination; the receiving identity, operation and content still need a decision.
Give processes an owner before they need cleanup
An operator reported orphaned processes (opens in a new tab) while the agent said everything was complete. Another described worktrees that fought for ports (opens in a new tab). These are author accounts, not incidents we reproduced. The second also promotes the author's tooling.
The architectural response is concrete: the harness should own a workload identity, the processes it started, its port allocation, its logs and the authority to stop it. A PID alone can be reused; a process name or occupied port does not prove ownership. Containers or suitably configured control groups can define a workload whose descendants belong together. systemd's control-group stop behavior (opens in a new tab) is an established primitive for this job.
A busy-port response should identify a conflict and allow selection of another approved port. It should not silently authorize terminating the listener. A process inventory is observation. Teardown is an action requiring ownership and authority. We have not tested that lifecycle design in this lab.
Deny an action without publishing the filter
A refusal need not explain the exact pattern, path exceptions or ways to rewrite a blocked request. Keep detailed diagnostics available to the operator with a correlation id. Give the agent the information needed to stop or use a specifically allowed recovery path.
For example, a proposed response could say “Permission denied. This action is outside the task policy. Do not retry through another tool. Reference: D-17.” The wording is illustrative, not a portable tool API or a tested defense. The model may ignore it; the resource boundary still needs to refuse the effect.
Turning every error into “bad request” is not sufficient. A terminal policy denial and a transient network failure call for different behavior. A timeout can also leave the external effect unknown. The uncertain-action record covers that case. No experiment here establishes that shorter errors reduce adaptive attacks.
Keep the boundary contract when the model changes
A new model may plan differently, call other tools or retry more aggressively. It should still encounter the same effective resource limits. Record the actual provider/model, harness version, policy version, tools and exception grants so that a reviewer can explain what changed.
That does not make models interchangeable in capability or the harness immutable. Adapter schemas, upgrades, plugins and unsandboxed fallbacks can change the enforced path. A budget dashboard also differs from a hard admission cap: every billable route and concurrent in-flight request must be accounted for before the cap is meaningful.
Since October 23, 2026 every one of the review's 24 scenarios carries a reference-fixture run with its own record; the runs grade our fixtures, not any product, and the records say where a real component (Docker networking, a LiteLLM proxy) was the subject. Use the harness boundary review to name the authority, the observer, the process owner, the stopping rule and the evidence still missing for one real workflow. It includes a field guide, an illustrative timeline, an editable record and 24 proposed evaluation scenarios covering files, lifecycle, network identity, budgets, evidence and changing tools. Those scenarios are all NOT RUN; they extend the review questions without extending this article's eight-case experimental claim.
Our research supports this question; it does not yet justify another privileged monitoring platform. Start with a boundary you can inspect and an effect you can establish. Keep the legitimate task in the comparison.
Found an error or a missing boundary? Send a correction or question. Please omit private traces and credentials.