# 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 ``` 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`