WARDEN-WP-0026 T01: capabilities-safe lane verification + incident note
T01 (done): canonical capabilities-based verify pattern in the fleet promotion checklist (catalog-lane-promotion.md) and applied to the railiance-backup and forgejo-admin lane playbooks. Verification proves allow/deny via `bao token capabilities` against the KV v2 data path, never `bao kv get`; a denied default-policy token-create is a pass, not a privileged-fallback trigger. T07 (progress): lessons-learned note for the 2026-07-16 CCR-2026-0004 disclosure (three root causes). Live re-verify + rotation block remain (depend on T06). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2ad8a53781
commit
ea98d6bf39
5 changed files with 161 additions and 3 deletions
57
history/2026-07-16-credential-disclosure-lessons.md
Normal file
57
history/2026-07-16-credential-disclosure-lessons.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Credential disclosure lessons — 2026-07-16
|
||||
|
||||
**Context:** buildup mode. Exposure was accepted; the value here is the learnings,
|
||||
not blame. Rotation of the exposed values is the operator's optional call, not a
|
||||
blocker (see WP-0026 T07).
|
||||
|
||||
## What happened
|
||||
|
||||
While verifying `CCR-2026-0004` (railiance offsite backup lane), a negative policy
|
||||
test was run as:
|
||||
|
||||
```bash
|
||||
BAO_TOKEN=$(bao token create -policy=default -field=token) bao kv get <path>
|
||||
```
|
||||
|
||||
The `bao token create` was **denied** (the workload role lacks it), so `BAO_TOKEN`
|
||||
was left unset and `bao kv get` fell back to the caller's **privileged login
|
||||
token**. The read succeeded and printed all three field values —
|
||||
`NC_WEBDAV_TOKEN`, `NC_WEBDAV_URL`, `AGE_PRIVATE_KEY` — into an agent session
|
||||
transcript (a logged context).
|
||||
|
||||
## Root causes
|
||||
|
||||
1. **The deny-test read the secret data path at all.** A negative test should
|
||||
prove *deny*, and proving deny never requires reading the value.
|
||||
2. **Silent privileged-token fallback.** When the scoped token creation failed,
|
||||
the command quietly used the caller's privileged token instead of failing.
|
||||
3. **The read landed in a logged context.** An agent session transcript is not a
|
||||
safe sink for secret material.
|
||||
|
||||
## Corrections (WARDEN-WP-0026, Strand A)
|
||||
|
||||
- **Verification never reads secret data.** Prove allow/deny with
|
||||
`bao token capabilities`, not `bao kv get`. If `bao token create -policy=default`
|
||||
is itself denied, that is a *pass* for the deny direction — never fall back to a
|
||||
privileged token. Canonical pattern:
|
||||
`wiki/playbooks/catalog-lane-promotion.md#capabilities-safe-lane-verification`
|
||||
(WP-0026 T01, applied to the forgejo and railiance-backup lane playbooks).
|
||||
- **Safe transport** for values that must move: env var, file, or response-wrapping
|
||||
token (`-wrap-ttl`) — never a stdout table (WP-0026 T02).
|
||||
- **Masking** as defense-in-depth in the warden wrapper (WP-0026 T03).
|
||||
- **Agent read-boundary + EXPOSED taint** on high-risk lanes, and per-lane
|
||||
**rotation guidance** (WP-0026 T04–T06).
|
||||
|
||||
## Deferred (Strand B — WARDEN-WP-0027)
|
||||
|
||||
Executable one-command mass rotation, graded lockdown / break-glass with a designed
|
||||
trust-root, and tamper-evident policy governance + reconcile are captured in
|
||||
`WARDEN-WP-0027` (backlog, gated on an activation trigger).
|
||||
|
||||
## References
|
||||
|
||||
- `WARDEN-WP-0026` — disclosure hygiene (Strand A)
|
||||
- `WARDEN-WP-0027` — governance/lockdown (Strand B, deferred)
|
||||
- `CCR-2026-0004-railiance-backup-offsite-lane.yaml` (railiance-platform)
|
||||
- `wiki/playbooks/railiance-backup-offsite-lane.md`
|
||||
- `.claude/rules/credential-routing.md`
|
||||
Loading…
Add table
Add a link
Reference in a new issue