Repository navigation
Validate that agent egress cannot bypass configured release controls #659
Description
Activity
Adding one route to the AC#1 inventory that I think behaves differently from the others listed.
Process crash artifacts. On a fatal signal with core disposition (SIGSEGV/SIGABRT from a native dependency, or an operator kill -QUIT), the kernel writes the gateway's address space to whatever /proc/sys/kernel/core_pattern designates. At mcp/proxy.py:1719 the full upstream response is held as a str in gateway memory before the #657 ceiling is applied, so a dump at that point contains payloads the gateway is in the act of withholding. CPython does not zero freed objects, so it also reaches back over earlier calls in the same process. This is not a side channel, it is a direct plaintext write to storage.
What makes it different from the listed routes is that the workload cannot mediate it. core_pattern is not namespaced: a process that is PID 1 in its own PID namespace and root in its own user namespace reads the host value and cannot write it, and I confirmed a crash there is captured by the host handler and stored outside the namespace. ulimit -c 0 is also weaker than it looks. With a piped core_pattern the kernel still enters the dump path and invokes the handler (WCOREDUMP set in the wait status); systemd-coredump declines to persist only because it reads the limit via the %c specifier, and a handler that ignores it writes the dump anyway. So the destination is a host property, which I think puts this inside AC#4 rather than only AC#6.
Relevant to the subprocess-inheritance clause in AC#1: RLIMIT_CORE is an inherited process attribute, and mcp/stdio.py:222 spawns children with no preexec_fn, so whatever the gateway carries, every stdio child gets. A single resource.setrlimit(RLIMIT_CORE, (0, 0)) at startup would cover the whole process tree, but per the above it is necessary rather than sufficient, so the host core_pattern probably has to become a published deployment assumption too.
@Yatsuiii each of these landed in #662, merged the same day: the host
core_patternis checked before plaintext admission and piped handlers refuse startup, since Linux ignoresRLIMIT_COREon a piped dump;RLIMIT_CORE=0is set hard and soft on the bridge and the agent, and the stdio tools inherit it. See the crash-artifacts row indocs/confinement.mdandcheck_core_patternintests/confinement/test_adapter.py. With #663 merged on 21 September every acceptance item here is delivered, so I am closing this; the published assumptions and untested channels are in the same doc.
Parent tracker: agentrust-io/.github#41
Problem and scope
Merged #657 supplies operator-owned tool and response sensitivity ceilings. Those checks do not mediate direct agent sockets, files, subprocesses, alternate model endpoints or every log sink.
Define a reusable confinement contract and exercise one supported reference deployment. Keep OS/runtime adapters explicit; do not claim that an SDK wrapper alone confines arbitrary agent code.
Acceptance criteria
Dependencies and boundaries
#124 owns policy enforcement inside the TEE; #462 owns measurement-bound signing-key custody. This issue owns mediation around that enforcement. Hardware-backed claims require those dependencies and measured application identity. Existing #657 is merged; do not reopen its completed scope or treat its unit tests as confinement evidence.
Reference implementation status (2026-09-18)
The checked criteria refer to the bounded native-Linux reference, with acceptance review still pending. #662 was approved and merged. Follow-up #663 at
a56f5abadds bridge/watchdog failure handling, live operator restrictions and audit/export probes.The hosted confinement run passed all 57 tests in 22.34 seconds; all 17 hosted checks passed, with two conditional skips. The
confinement-evidenceartifact contains independently observed delivery/termination outcomes and host versions. The full local suite passed 1,992 tests with 25 skips and 89.46% coverage.Protected runs delivered only to approved sinks. Network, file, logging and sink-ceiling mutations produced the intended leaks. A separate payload-free lease watchdog stopped the container after bridge kill/pause; watcher death also stopped the exchange. Removing the watcher left the adversarial container alive. Live revocation/restoration preserves the original cMCP sensitivity and sink ceilings; removing the gate fails the queued-call regression. Invalid/stale operator revisions close admission until a valid newer update.
Actual SQLite records, chain entries, SDK-exported spans and logs were inspected for response echo, upstream errors, malformed stdout and stderr echo. Two tests first reproduced private-data leaks in audit-observer/OTel failure diagnostics, which now omit sink representations and exception tracebacks. The host core-handler refusal and hard core limits from #662 remain in force.
The route inventory, reproducible commands and trust assumptions are in
docs/confinement.md. Keep this issue open for review of #663. The reference assumes a surviving trusted host, watcher and responsive daemon; simultaneous watcher/bridge loss, pre-admission orphan collection and host-wide recovery are outside its claim. Live restrictions are not arbitrary hot catalog/classifier replacement or rollback-protected policy storage. Arbitrary exporters, sensitive metadata/hashes, downstream custody and covert channels are not certified by literal canary tests. No hardware-backed guarantee or memory-erasure claim is made.