2026-08-19 23:08:00 +02:00
---
id: RISK-F-0003
type: finding
title: "ops-warden agent read-boundary does not fire on ungraded catalog lanes"
2026-09-01 02:41:32 +02:00
status: fixed
owner: risk-nexus
2026-08-19 23:08:00 +02:00
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
2026-09-01 02:41:32 +02:00
fix_tracking: WARDEN-WP-0032-T05 / T06 (done 2026-08-22)
RISK-WP-0001 T01-T06,T08: the four instruments, the index, and the first grading
Severity (impact x likelihood, fidelity modifier for controls that lie,
headline-vs-constraint, build-mode double grade, the floor), disclosure
(publish/embargoed/restricted, and the build-mode deferral re-taken and
narrowed with RISK-F-0001 in hand), escalation (the five INTENT triggers
settled plus an ordering-hazard trigger the RISK-F-0002 case forced;
proposed, awaiting the custodian), review (intervals, what a review is,
what missing one produces, the production re-score).
Then applied: RISK-F-0001 critical/embargoed/escalated, RISK-F-0002
medium with a high constraint on RISK-F-0001's remediation, filed as a
peer and escalated only on the ordering, RISK-F-0003 high/embargoed/no
escalation. No unset field remains.
REGISTER.md is generated; make check reports overdue, stalled, ungraded
and unanswered escalations without changing anything.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:29:39 +02:00
# Graded by risk-nexus 2026-08-19 — docs/rulings/2026-08-19-first-grading.md
Adaptive check cadence: the interval is earned, not assigned
Operator ruling 2026-08-20. Severity no longer sets the review interval.
A check that comes back clean climbs one rung — instant, 1h, 8h, 24h,
48h, 96h, 7d, 14d, 1mo, 1q — and anything wrong drops straight back to
instant. A quarter is the ceiling. The operator may defer an instant
finding to a stated date; that is the only other way off the bottom rung.
The rung is the point: it says how stable the estate has been on that
matter, which is information severity does not carry. Volatile things get
attention automatically; quiet things stop consuming it; neither
judgement has to be made by a person who might be busy.
Escalation trigger 5 rebased onto the ladder — fourteen days at the
bottom rung, whether that is failing checks or no checks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 07:43:51 +02:00
severity: medium
severity_at_production: medium
severity_superseded: "high (2026-08-19) — the CLI-layer gap is mitigated"
RISK-WP-0001 T01-T06,T08: the four instruments, the index, and the first grading
Severity (impact x likelihood, fidelity modifier for controls that lie,
headline-vs-constraint, build-mode double grade, the floor), disclosure
(publish/embargoed/restricted, and the build-mode deferral re-taken and
narrowed with RISK-F-0001 in hand), escalation (the five INTENT triggers
settled plus an ordering-hazard trigger the RISK-F-0002 case forced;
proposed, awaiting the custodian), review (intervals, what a review is,
what missing one produces, the production re-score).
Then applied: RISK-F-0001 critical/embargoed/escalated, RISK-F-0002
medium with a high constraint on RISK-F-0001's remediation, filed as a
peer and escalated only on the ordering, RISK-F-0003 high/embargoed/no
escalation. No unset field remains.
REGISTER.md is generated; make check reports overdue, stalled, ungraded
and unanswered escalations without changing anything.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:29:39 +02:00
impact: I4
likelihood: L2
fidelity_modifier: false
production_rescore: false
2026-09-01 02:41:32 +02:00
disclosure: public
publication: pending-handover
publication_id: risk-f-0003-ops-warden-agent-read-boundary-blind-spot
publication_path: "findings/ops-warden-agent-read-boundary-blind-spot/v1/index.html"
publication_subtitle: "An omitted catalog grade silently bypassed the agent credential boundary; omission now fails safe and CI rejects it."
revision: "fixed-1"
last_reviewed: "2026-09-01"
review_interval: 6m
embargo_lifted: "2026-08-22 — catalog omission fails safe, CI requires explicit grades, and RISK-F-0009's direct-OpenBao layer is fixed"
embargo_was_since: "2026-08-19"
RISK-WP-0001 T01-T06,T08: the four instruments, the index, and the first grading
Severity (impact x likelihood, fidelity modifier for controls that lie,
headline-vs-constraint, build-mode double grade, the floor), disclosure
(publish/embargoed/restricted, and the build-mode deferral re-taken and
narrowed with RISK-F-0001 in hand), escalation (the five INTENT triggers
settled plus an ordering-hazard trigger the RISK-F-0002 case forced;
proposed, awaiting the custodian), review (intervals, what a review is,
what missing one produces, the production re-score).
Then applied: RISK-F-0001 critical/embargoed/escalated, RISK-F-0002
medium with a high constraint on RISK-F-0001's remediation, filed as a
peer and escalated only on the ordering, RISK-F-0003 high/embargoed/no
escalation. No unset field remains.
REGISTER.md is generated; make check reports overdue, stalled, ungraded
and unanswered escalations without changing anything.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:29:39 +02:00
escalation: none
2026-09-01 02:41:32 +02:00
date_fixed: "2026-08-22"
last_checked: "2026-09-01T00:32:44Z"
next_check: "2026-09-01T00:32:44Z"
cadence: instant
clean_streak: 0
RISK-WP-0001 T01-T06,T08: the four instruments, the index, and the first grading
Severity (impact x likelihood, fidelity modifier for controls that lie,
headline-vs-constraint, build-mode double grade, the floor), disclosure
(publish/embargoed/restricted, and the build-mode deferral re-taken and
narrowed with RISK-F-0001 in hand), escalation (the five INTENT triggers
settled plus an ordering-hazard trigger the RISK-F-0002 case forced;
proposed, awaiting the custodian), review (intervals, what a review is,
what missing one produces, the production re-score).
Then applied: RISK-F-0001 critical/embargoed/escalated, RISK-F-0002
medium with a high constraint on RISK-F-0001's remediation, filed as a
peer and escalated only on the ordering, RISK-F-0003 high/embargoed/no
escalation. No unset field remains.
REGISTER.md is generated; make check reports overdue, stalled, ungraded
and unanswered escalations without changing anything.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:29:39 +02:00
graded_by: risk-nexus
ruling: RISK-RULING-2026-08-19
2026-09-01 02:41:32 +02:00
checked_by: "codex/risk-nexus"
2026-08-19 23:08:00 +02:00
---
# RISK-F-0003 — the agent read-boundary has a fourteen-lane blind spot
2026-08-19 23:45:56 +02:00
> **Reporter update 2026-08-19 — exposure closed, structural fix outstanding.**
> All 14 ungraded lanes now carry an explicit `risk` grade (17 high, 10
> standard, 0 ungraded) and the read-boundary fires on them; verified exit 7
> with `WARDEN_AGENT_ID` set. The rule is recorded as ops-warden `ADR-0007`.
> **Still open:** nothing yet prevents a *new* lane being added ungraded
> (`WARDEN-WP-0032-T06`), and it remains unverified whether OpenBao's
> `agent-high-risk-boundary` policy covers these paths. `status` moved to
> `mitigated` by the reporter; severity remains risk-nexus's to set.
2026-08-19 23:08:00 +02:00
## 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.
2026-08-19 23:24:34 +02:00
**Update 2026-08-19 — a third direction, and the one being taken.** The operator
has directed that the default derive from **maturity context** : in an early or
experimental context an absent grade is tolerable and explicitly accepted; in a
production context an absent grade resolves to `high` , or `critical` where the
context is critical. This validates against the data here — all five exposed
lanes are owned by production-serving components, so the rule would have caught
every one.
The durable form of that is a zone-model question (`ZONE-WP-0001-T03` ), because
the `M0` -`M3` maturity ladder that would drive it has no join to catalog lanes
today. That work is months out, so the two are being run separately: the five
lanes are graded explicitly now under `WARDEN-WP-0032-T05` , and the structural
fix that makes absence impossible follows under `WARDEN-WP-0032-T06` .
Note for whoever sets severity: `.repo-classification.yaml` `category` is **not**
usable as the maturity signal. `railiance-platform` , which runs production
OpenBao and owns three of the five lanes above, is `category: tooling` .
2026-08-19 23:08:00 +02:00
## 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
RISK-WP-0001 T01-T06,T08: the four instruments, the index, and the first grading
Severity (impact x likelihood, fidelity modifier for controls that lie,
headline-vs-constraint, build-mode double grade, the floor), disclosure
(publish/embargoed/restricted, and the build-mode deferral re-taken and
narrowed with RISK-F-0001 in hand), escalation (the five INTENT triggers
settled plus an ordering-hazard trigger the RISK-F-0002 case forced;
proposed, awaiting the custodian), review (intervals, what a review is,
what missing one produces, the production re-score).
Then applied: RISK-F-0001 critical/embargoed/escalated, RISK-F-0002
medium with a high constraint on RISK-F-0001's remediation, filed as a
peer and escalated only on the ordering, RISK-F-0003 high/embargoed/no
escalation. No unset field remains.
REGISTER.md is generated; make check reports overdue, stalled, ungraded
and unanswered escalations without changing anything.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:29:39 +02:00
## Register ruling — 2026-08-19
`high` (`I4` × `L2` ), embargoed until the five `exec_capable` lanes are graded
under `WARDEN-WP-0032-T05` , no escalation.
**Graded on its worst lane.** Four of the five are `I3` -shaped — a publish
token, an OIDC login, an ingestion key, a hub write token, each bad inside its
own system. `openbao-api-key` is not: it reaches the store the estate's other
secrets live in, and a disclosure there propagates past every boundary the
others respect.
**Likelihood `L2` ** — an agent session with `WARDEN_AGENT_ID` is a foothold the
estate does grant. The register holds the line this finding drew: the exposed
population is not established, so it is neither assumed zero nor assumed large,
and the unverified OpenBao `agent-high-risk-boundary` coverage is a review
question rather than an assumption in either direction. Confirming that
coverage for these five paths would lower the grade.
**No fidelity modifier, and it was close.** `ADR-0004` reads categorical while
the implementation is opt-in, so the documentation asserts a boundary that does
not exist for 14 lanes. The modifier is scoped to attestations a system
produces at runtime, and documentation drift is not that. But if any compliance
evidence anywhere cites `ADR-0004` as implemented, that *is* a false
attestation and a separate finding. This register has not looked, and says so
rather than assuming.
**No escalation.** Known, owned, tracked (`WARDEN-WP-0032-T05` for the five
lanes, `WARDEN-WP-0032-T06` for the structural fix), and moving. Severity alone
deliberately does not reach the operator.
**On the maturity-context direction**, which is the operator's and not
re-decided here: the note that `.repo-classification.yaml` `category` cannot
carry the signal is confirmed from this repo's own registration work today.
`railiance-platform` runs production OpenBao and owns three of the five lanes
while classified `tooling` ; `risk-nexus` classified itself with the same
vocabulary an hour ago. The maturity ladder needs its own field, and that is
`ZONE-WP-0001-T03` 's to build.
Reasoning: `docs/rulings/2026-08-19-first-grading.md` .
## Reviews
- **2026-08-19** — graded. Next review 2026-09-18 (`high` → 30 days).
Open at review: OpenBao policy coverage of the five paths; whether
`WARDEN-WP-0032-T05` has landed; whether any compliance evidence cites
`ADR-0004` as implemented.
Adaptive check cadence: the interval is earned, not assigned
Operator ruling 2026-08-20. Severity no longer sets the review interval.
A check that comes back clean climbs one rung — instant, 1h, 8h, 24h,
48h, 96h, 7d, 14d, 1mo, 1q — and anything wrong drops straight back to
instant. A quarter is the ceiling. The operator may defer an instant
finding to a stated date; that is the only other way off the bottom rung.
The rung is the point: it says how stable the estate has been on that
matter, which is information severity does not carry. Volatile things get
attention automatically; quiet things stop consuming it; neither
judgement has to be made by a person who might be busy.
Escalation trigger 5 rebased onto the ladder — fourteen days at the
bottom rung, whether that is failing checks or no checks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 07:43:51 +02:00
## Check — 2026-08-20: mitigated on one layer, `high` → `medium`
`ops-warden` reports all 17 high-risk lanes now exiting 7 on
`warden access --fetch` with `WARDEN_AGENT_ID` set, verified under
`WARDEN-WP-0032-T05` /`T06` . The 14 ungraded lanes are graded; the boundary
fires. The live gap this finding described is closed on the CLI layer.
**Not clean, so the cadence stays at `instant` .** Something moved, and under
the ladder that resets the clock rather than earning a longer one. The next
check is the one that can start climbing.
**`high` → `medium` .** What remains is the omission shape rather than the
instance: whether a future lane can still be added without a grade. That is
`WARDEN-WP-0032-T06` , and the durable form of the operator's maturity-context
rule is `zone-engine` 's (`RISK-N-0004` ). Not `low` , because "graded by hand
once" is not the same as "cannot be ungraded again".
**The embargo condition changed rather than being met.** The original condition
— the five `exec_capable` lanes graded — is satisfied. But `RISK-F-0009` shows
the *second* layer, the OpenBao deny set that protects the direct `bao kv get`
path, covers 6 of 17 high-risk lanes. Publishing this finding now would name
lanes that are still reachable by the path this control exists to close. The
condition is therefore re-pointed at `RISK-F-0009` .
That is the disclosure rule working across two findings rather than one: what
matters is whether the text shortens a path, not whether this particular
finding's own fix has landed.
**Verification limit, recorded rather than assumed:** the mitigation is
`ops-warden` 's report and this register has not probed it. Their operator token
is expired, which is also why `RISK-F-0009` rests on a file comparison.
2026-08-20 12:03:12 +02:00
- **2026-08-20** — clean check: checked against the inbox and the owner's record; nothing moved. Cadence instant → 1h (1 clean in a row); next check 2026-08-20 11:02Z.
2026-08-21 08:34:30 +02:00
- **2026-08-21** — clean check: fix state read from the owner's file: WARDEN-WP-0032-T05 done; nothing else moved. Cadence 1h → 8h (2 clean in a row); next check 2026-08-21 14:32Z.
2026-09-01 02:41:32 +02:00
## Closure — 2026-09-01: omission is no longer permissive
The remaining structural task is done. `RouteEntry` now resolves an absent or
unknown grade fail-safe, `is_graded` exposes the distinction, and CI rejects a
catalog lane without an explicit grade. The current focused Warden regression
set passes (**137 tests**), including the omission and OpenBao coverage checks.
The dependent direct-OpenBao gap is also fixed under `RISK-F-0009` . There is no
remaining live or structural part of this finding, so it moves from `mitigated`
to `fixed` and its embargo lifts.
- **2026-09-01** — not clean: WARDEN-WP-0032-T06 and the dependent OpenBao coverage are complete; status fixed and embargo lifted. Cadence 8h → instant; checked again immediately.