Records (never refuses) a curl/wget to a host fetched content named, when the
command expands something at run time: the GET-exfil shape the floor leaves
open. The designed rule — body-carrying calls to tainted hosts — is dominated
by curl-body/curl-upload/wget-body, which already refuse every body, so it
would have shadowed nothing and looked like a clean result.
One case table drives the Rust predicate and the generated shell; they agree on
all ten cases (attack spellings, link-following, untainted expansion, subdomain
limit, non-fetches), and every case exits 0. The gate reads the file the tap
writes on both tiers (tested).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The "derived from untrusted content" half of ActGov's invariant (no outbound
action whose target came from untrusted content). Observed only; no rule
reads it yet.
- the tap runs a node extractor only when a payload could be a fetch
(WebFetch, WebSearch, curl/wget in command position) and appends the
response's URL hosts, minus the agent's own target, to
untrusted-hosts.txt beside the tap — a path hook-files already protects
- capped at 500, deduplicated, and the tap still always exits 0
- both tiers drain it per finished phase into a taint.hosts event
- shell-tested against the generated hook with the real node; the test caught
`grep -r curl docs` being read as a fetch
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Four measurements decide the shape, all taken today:
1. --allowedTools is not an enforcement boundary. ListAgents and
ScheduleWakeup ran on microvm missions whose list is Read Edit Write
Bash Agent. The flag governs prompting, not availability, so any
task-permission layer must be enforced by our own gate.
2. The guest already has every tool's output on disk (the tap appends the
whole payload, tool_response included), so taint is computable
guest-locally with no network call and no added latency.
3. The taint store would already be protected — the hook-files rule
refuses reads and writes to /root/toolhooks from both Bash and the
write tools.
4. Provenance is a CONTAINER-tier control. A microVM reaches only the
provider and the forge through a name-matched CONNECT allow-list; a
container reaches any public host. Saying it matters equally on both
would be padding.
Task permission: a per-phase "agent_tools" key (NOT "tools", which
security_scan already owns), defaulted from what phase kinds actually
used, enforced by the gate. Provenance: taint hostnames out of fetched
responses, deny an outbound call WITH A BODY whose target is one of them
— the asymmetry being that reading a host a page mentioned is research
and sending data to it is the attack. String taint is rejected outright
as a false-positive generator, which is this module's cardinal sin.
Both ship in shadow (gate.would_deny) first, because today's corpus is
171 tool calls and 15 curl invocations and cannot validate a rule.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WZb5A2kfVfjpdwSochkuHz