From f5147c2987fff552c6420d87ac10b2ec06f69936 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 19 Aug 2026 23:08:00 +0200 Subject: [PATCH] =?UTF-8?q?RISK-F-0003=20=E2=80=94=20ops-warden=20agent=20?= =?UTF-8?q?read-boundary=20blind=20spot=20on=20ungraded=20lanes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADR-0004 reads as a categorical rule; the implementation is an opt-in list. is_high_risk is risk == "high", and risk is optional — 14 of 27 catalog lanes carry no value, so the boundary never fires for them. Five are exec_capable, so warden access --fetch can stream a real value to an agent session. Reported by ops-warden about ops-warden, found while partitioning the estate for zone-engine's ZONE-WP-0001-T02. Severity, disclosure and escalation left unset — those are risk-nexus's to set. Co-Authored-By: Claude Opus 5 --- ...ops-warden-read-boundary-ungraded-lanes.md | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md diff --git a/findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md b/findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md new file mode 100644 index 0000000..c586d30 --- /dev/null +++ b/findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md @@ -0,0 +1,106 @@ +--- +id: RISK-F-0003 +type: finding +title: "ops-warden agent read-boundary does not fire on ungraded catalog lanes" +status: open +reported_by: ops-warden +reported_via: ops-warden +routed_by: ops-warden +date_reported: "2026-08-19" +system: ops-warden +environment: production +fix_owner: ops-warden +fix_tracking: unset +# risk-nexus's fields, deliberately left unset by the reporter. +severity: unset +disclosure: unset +escalation: unset +--- + +# RISK-F-0003 — the agent read-boundary has a fourteen-lane blind spot + +## What is true + +`ADR-0004` (ops-warden) states that high-risk lanes refuse raw value streaming +to agent sessions. It is implemented in `src/warden/cli.py:1245`: + +```python +if raw_value_stream and entry.is_high_risk and agent_id: +``` + +and `is_high_risk` is defined in `src/warden/routing/models.py:123` as: + +```python +return self.risk == "high" +``` + +`risk` is an **optional** field on a catalog entry. Of the 27 entries in +`registry/routing/catalog.yaml`, **14 carry no `risk` value at all**. For those, +`is_high_risk` is `False`, so the boundary never fires regardless of what the +lane actually vends. + +Five of the fourteen are `exec_capable: true`, meaning `warden access --fetch` +can proxy a real value for them: + +| Lane | Owner | Status | +| --- | --- | --- | +| `openbao-api-key` | railiance-platform | active | +| `whynot-design-npm-publish` | railiance-platform | active | +| `key-cape-oidc-login` | key-cape | active | +| `issue-core-ingestion-api-key` | railiance-platform | active | +| `reuse-surface-hub-write-token` | railiance-platform | active | + +For these five, an agent session with `WARDEN_AGENT_ID` set can stream a secret +value to stdout, which is the disclosure pattern of 2026-07-16 that WP-0026 and +`ADR-0004` were written to prevent. The control is not bypassed; it is simply +never reached. + +## Why it matters beyond these five + +The failure mode is **omission, not error**. Adding a lane without a `risk` +value produces a lane outside the boundary, silently, with no warning at load +and nothing in CI that notices. Every future lane inherits this default. The +nine other ungraded lanes are not `exec_capable` today, but `exec_capable` is +itself an editable field. + +`ADR-0004` reads as a categorical rule. The implementation is an opt-in list. + +## Exposure — stated only as far as ops-warden can support it + +- ops-warden is the affected system and owns the catalog, the ADR, and the code. +- `WARDEN_AGENT_ID` is set by agent harnesses; ops-warden has not enumerated + which sessions currently set it, so the population actually exposed is + **not established** and should not be assumed to be zero or large. +- There is a second, independent layer for OpenBao-backed lanes: the OpenBao + policy `agent-high-risk-boundary` denies data-read for agent tokens on the + paths it covers. Whether it covers these five paths **has not been verified + by ops-warden** and should be checked against the live policy rather than + inferred — the paths were graded by the same omission this finding is about. +- No evidence of an actual disclosure through these lanes has been sought or + found. This is a control gap, not a known incident. + +## How it was found + +Doing `ZONE-WP-0001-T02` (zone-engine) — partitioning the estate for the +security-zone model. Grading every lane on `risk` was a prerequisite for +deriving zone membership, and the count of ungraded lanes is what surfaced it. + +## Suggested direction, not a prescription + +Two candidate fixes, both ops-warden's to choose between: + +1. **Invert the default.** Treat absent `risk` as high, so a new lane is + protected until deliberately graded down. Fails safe; may be noisy. +2. **Make `risk` required**, enforced at catalog load and in CI, so an ungraded + lane cannot be committed. Fails loud; requires grading 14 lanes now. + +Either way the grading is real work with real judgement in it, and the five +`exec_capable` lanes are the ones that matter first. + +## Related + +- ops-warden `ADR-0004` — high-risk lanes refuse raw value streaming +- ops-warden `WP-0026` — disclosure hygiene, safe fetch transports +- `wiki/playbooks/agent-read-boundary.md` +- `RISK-F-0002` — ops-warden sign ungated (same system, different control) +- `zone-engine` `ZONE-WP-0001-T02` — the work that surfaced this