risk-nexus/findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md
tegwick d5147bfaea Typed, dated, defaulted waits — and cut the four-hop chain
The register had nine waits in four days, one four hops deep: F-0003's
embargo waited on F-0009, which waited on railiance-platform, which
waited on live OpenBao verification, which waited on a credential nobody
has. No single link was wrong, which is why it needed a rule.

docs/method/dependencies.md: the register never waits to decide, it
decides and revises. Every wait carries who, what, since, what it would
change, what happens if nobody answers, and the date that default
applies. Depth one — a record never waits on a record that is itself
waiting. Defaults are dates and are pessimistic: silence costs the grade
the evidence supports rather than buying a softer one, and owners are
told the default in advance because a default nobody was warned about is
an ambush.

Applied: F-0009's embargo now lifts on railiance-platform reporting
coverage, with live verification as a refinement rather than a condition,
cutting the F-0003 chain from four hops to two. All eight open waits are
typed with defaults. make check reports them with age, owner and default
date, flags defaults come due, and catches depth-two violations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 22:34:56 +02:00

9.1 KiB
Raw Blame History

id type title status reported_by reported_via routed_by date_reported system environment fix_owner fix_tracking filed_as answers related severity severity_at_production impact likelihood fidelity_modifier production_rescore disclosure embargo_condition embargo_since escalation last_checked next_check cadence clean_streak waiting_on graded_by ruling
RISK-F-0009 finding agent-high-risk-boundary denies 6 of 17 high-risk lanes; the direct bao path is unprotected for the rest open ops-warden ops-warden ops-warden 2026-08-20 railiance-platform production railiance-platform unset RISK-F-0004 by ops-warden; renumbered by risk-nexus 2026-08-20 (id collision) RISK-F-0003
RISK-F-0003
high high I4 L2 false false embargoed railiance-platform reports the deny set covers every high-risk lane with a KV path (live verification refines the grade, it is not the condition) 2026-08-20 none 2026-08-20T10:02:42Z 2026-08-20T11:02:42Z 1h 1
who what since would_change default default_at
railiance-platform report whether the deny set covers every high-risk lane with a KV path 2026-08-20 embargo lifts on coverage; live verification would refine the grade but is not required for it the eight uncovered paths stand as recorded and the finding is re-raised 2026-09-03
risk-nexus RISK-RULING-2026-08-20

RISK-F-0009 — the OpenBao half of the agent read-boundary covers a third of the lanes

What is true

ADR-0004 (ops-warden) is enforced in two independent layers:

  1. ops-warden's CLI — warden access <lane> --fetch exits 7 when WARDEN_AGENT_ID is set and the lane is high-risk. Verified working for all 17 high-risk lanes as of 2026-08-20 (WARDEN-WP-0032-T05/T06).
  2. OpenBao policy agent-high-risk-boundary (railiance-platform/openbao/policies/agent-high-risk-boundary.hcl) — denies data read and permits metadata read for agent tokens.

Layer 1 protects the ops-warden path. Layer 2 is the one that protects the path an agent actually takes when it bypasses ops-warden — a direct bao kv get, which is the 2026-07-16 disclosure vector.

Comparing the policy's deny list against ops-warden's catalog:

  • 17 lanes graded risk: high
  • 5 data paths denied by the policy
  • 6 high-risk lanes covered (one policy path serves two lanes)
  • 8 high-risk lanes with a concrete KV path that the policy does not deny
  • 3 high-risk lanes with no KV path (policy not applicable)

Not covered:

Lane KV path Newly graded 2026-08-19?
rapp-qonto-keycape-client platform/workloads/rapp-qonto/keycape-client no — already high
agent-harness-forgejo-deploy platform/workloads/agent-harness/forgejo-deploy-key no — already high
email-connect-transactional platform/workloads/email-connect/transactional no — already high
scaleway-bootstrap platform/workloads/railiance/scaleway/bootstrap no — already high
whynot-design-npm-publish platform/workloads/coulomb/whynot-design/npm-publish yes
audit-core-senders platform/workloads/audit-core/senders yes
ops-warden-warden-sign-token credential-broker grant, not a KV path yes
openbao-api-key platform/workloads/<domain>/<workload>/<bundle> — a pattern, not a path yes

Four of the eight were already graded high before this analysis. The divergence is therefore pre-existing and not a consequence of the 2026-08-19 regrade; the regrade only made it visible by making the two lists comparable.

Why it matters

ops-warden's layer can be bypassed by not using ops-warden. An agent session holding a workload-kv-read-* policy can bao kv get these paths directly, and for the eight above nothing denies it. The playbook (ops-warden/wiki/playbooks/agent-read-boundary.md) already states that an agent token carrying agent-high-risk-boundary must not also carry the lane's workload-kv-read-* policy — but that is an instruction to whoever mints the token, not a mechanism.

Exposure — stated only as far as ops-warden can support it

  • The comparison above is static, from the policy file in the railiance-platform checkout and ops-warden's catalog. It has not been confirmed against the live OpenBao. The operator token available to ops-warden is expired (bao token lookup → 403), so bao policy read and bao token capabilities could not be run. The deployed policy may differ from the file.
  • Whether any agent token currently carries agent-high-risk-boundary at all, and whether any carries it together with a workload-kv-read-* policy, is not established. If no agent tokens exist, exposure is theoretical.
  • openbao-api-key is a routing lane whose path_template is a pattern rather than an address; it is listed for completeness but probably cannot be expressed as a policy deny and should be handled by grading the concrete lanes it resolves to.
  • No evidence of an actual disclosure through these lanes has been sought or found.

Suggested direction, not a prescription

The two lists should be generated from one source rather than maintained in two places — that is what let them drift for four lanes without anyone noticing. ops-warden's catalog already carries risk and path_template per lane and could emit the deny set; railiance-platform owns whether to consume it. A check that fails when a high-risk lane has no corresponding deny would turn this from an audit into an invariant.

  • RISK-F-0003 — the ops-warden-side blind spot, mitigated 2026-08-19
  • ops-warden ADR-0004, ADR-0007
  • ops-warden/wiki/playbooks/agent-read-boundary.md
  • railiance-platform/openbao/policies/agent-high-risk-boundary.hcl

Register ruling — 2026-08-20

Renumbered from RISK-F-0004. ops-warden filed it as RISK-F-0004, which this register had already assigned to tenant-engine's unfiltered event read hours earlier. Earlier id keeps it; the newcomer moves. Nothing about the finding changes, and the filing contract now says how ids are allocated so the next reporter does not hit this.

high (I4 × L2), embargoed, no escalation.

I4 on the worst uncovered lane. Eight high-risk lanes have a concrete KV path the policy does not deny. Most are I3-shaped inside their own system; scaleway-bootstrap and agent-harness-forgejo-deploy are not — cloud account bootstrap credentials and a forge deploy key propagate past the system that holds them.

L2. It needs an agent token carrying a workload-kv-read-* policy, which the estate does grant. The register holds ops-warden's two stated limits rather than resolving them in either direction: the comparison is static against the policy file because their operator token is expired (bao token lookup → 403), so the deployed policy may differ; and whether any agent token currently carries agent-high-risk-boundary together with a workload-kv-read-* policy is not established.

No fidelity modifier, same call as RISK-F-0003. ADR-0004 describes two independent layers and one of them covers a third of the lanes, so the documentation overstates the control — but the modifier is scoped to attestations produced at runtime, not to documentation drift. Noted twice now in the same system; if it recurs a third time the modifier's scope is what should be re-examined, not the finding.

No escalation. railiance-platform owns the policy, ops-warden owns the catalog, and they have not disagreed about anything — trigger 4 needs a failed routing exchange, not merely two repos. ops-warden's suggestion that the deny set be generated from the catalog rather than maintained twice is routed as a suggestion, which is what it was offered as.

The pre-existing point is the important one. Four of the eight uncovered lanes were already graded high before the 2026-08-19 regrade. The divergence is not a consequence of that work; the regrade only made the two lists comparable enough to see it. A register that took credit for finding a fresh defect here would be misreading its own evidence.

Disclosure: embargoed, and it changes RISK-F-0003's embargo too. This names eight live KV paths that nothing denies.

One expired credential is blocking verification of both this finding and RISK-F-0003's mitigation. That is not a finding — nothing is wrong with the estate because a token expired — but it is why two gradings here rest on file comparison rather than a probe, and the register says so rather than implying otherwise.

Reviews

  • 2026-08-20 — renumbered, graded. Cadence starts at instant: nothing about this has been checked twice yet. Open at the next check: does the deployed policy match the file; do any agent tokens carry both policies; has railiance-platform taken the catalog-generated deny set.
  • 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.