--- id: ops-warden-adr-0004 type: adr title: "ADR-0004 — High-risk lanes refuse raw value streaming to agent sessions" domain: infotech repo: ops-warden status: accepted version: "1.1" revision: "2" owner: ops-warden binds: "ops-warden; any agent runtime calling warden access" created: "2026-07-20" updated: "2026-09-04" last_reviewed: "2026-09-04" review_interval: 6m enforced_by: "src/warden/access.py + src/warden/cli.py (exit 7); OpenBao policy agent-high-risk-boundary" supersedes: "" successor: "" --- # ADR-0004 — High-risk lanes refuse raw value streaming to agent sessions ## Status Accepted. Decided during WARDEN-WP-0026 (credential disclosure hygiene), in response to a real disclosure on 2026-07-16. ## Context On 2026-07-16 a secret value reached a captured stdout. The mechanism was ordinary: `bao kv get -field=X` in an agent session. Nothing was misconfigured and nobody misused a tool. The value was read correctly, by an authorized caller, using the documented command — and an agent session records its stdout, so the value landed in a transcript that outlives the shell. This is a structural mismatch, not a mistake to train away. Agent sessions are logged by design; that is what makes them reviewable. A human at a terminal sees a value and it scrolls away. An agent "seeing" a value writes it into a durable context that may be stored, replayed, or sent to an inference provider. Guidance alone will not fix it. The command is correct, it is in every runbook, and the next agent that needs the value will reach for it. ## Decision **When `WARDEN_AGENT_ID` is set and the catalog lane is `risk: high`, ops-warden refuses to stream the raw value and exits 7.** The agent is not blocked from doing its work — `--out`, `--exec`, `--wrap` and `--fingerprint` all remain available. It is blocked from doing its work *in a way that writes the secret into a transcript*. **Revision 2 also recognizes the issued coding-agent subject.** When `WARDEN_POLICY_SUBJECT` is the KeyCape-issued `service:codex:railiance-platform` identity, the same refusal applies without `WARDEN_AGENT_ID`. The legacy variable remains a fail-toward-safety fallback. Ops-warden reads this identity marker; it does not validate the token or decide whether the principal is authorized. **The boundary is enforced at the credential store as well as at the CLI.** The OpenBao policy `agent-high-risk-boundary` denies data-read on those paths for agent tokens, allowing metadata and capabilities only. A control that lives solely in our own CLI is a control that ends the moment someone calls `bao` directly. **Verification must not require a read.** To check a lane, use `bao token capabilities` — allow/deny — never a read of the value. This is the specific habit the disclosure taught us to break. **Exposure is reportable without reading.** `warden taint ` reports KV v2 `custom_metadata` (`exposed_at`, `exposed_version`) and touches no secret data. ## Consequences **Agents can still do everything they could before, by a different route.** `--exec` covers nearly every real case: the child process gets the value in its environment, the agent never sees it. The friction is deliberate and small. **Exit 7 is a contract other runtimes depend on.** It is a distinguishable code, not a generic failure, so a caller can tell "refused by boundary" from "lane broken" and retry correctly. Changing it is a breaking change to every agent runtime. **`risk: high` becomes a load-bearing catalog field** rather than documentation. Classifying a lane now changes runtime behaviour, so it must be set deliberately. **We accept that `--unsafe-stdout` still exists for humans.** The CLI recognizes the issued subject when the runtime presents it and otherwise relies on `WARDEN_AGENT_ID`; both markers remain caller-visible and therefore advisory. This ADR raises the floor for cooperating runtimes and hardens the store behind them; it does not claim to stop a determined caller. The OpenBao `agent-high-risk-boundary` policy is the enforced control. ## Related - `wiki/playbooks/agent-read-boundary.md` - `wiki/playbooks/exposed-taint.md` - `ADR-0002` — the conduit rule this narrows for agent callers