docs: INCIDENT — I printed the console password to the transcript
gate / gate (push) Has been cancelled
gate / conformance (push) Has been cancelled

A kubectl jsonpath with {range .data}{@}{end} dumped the unifi Secret's data
map, putting the base64 console-password in the session transcript. Exactly the
constraint I put in every agent brief, broken by my own careless verification
command.

Exposure bounded: 0 commits contain it (git log -S), the capturing scratch file
was shredded, and a repo-wide grep finds nothing on disk. Critically it is not
yet a live credential — the Secret was created two days after the running VMI,
whose volume list is rootdisk and cloudinit only, so the UOSDATA disk was never
attached, install-uos never ran, and the ubuntu account is still locked.

Action recorded with the ordering that matters: rotate console-password BEFORE
recreating the VMI, so the leaked value never becomes valid.

Lesson: checking a Secret's existence never needs its values. Listing .data's
keys or .metadata.name answers the question; dumping .data answers one nobody
asked.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
jakman85andClaude Opus 5 committed 2026-09-18 21:39:42 -05:00
1 parent 14d5ccbadd
commit 6a4dc0ada7
1 file changed
+36
+36
View File
@@ -4229,3 +4229,39 @@ both fields as literal `REPLACE-ME`, unlike every other `*.sops.yaml` here. `sop
failed with "sops metadata not found", and Flux would have created the Secret containing the failed with "sops metadata not found", and Flux would have created the Secret containing the
placeholder strings. Encrypted in place, round-trip verified. Both fields need setting, not just the placeholder strings. Encrypted in place, round-trip verified. Both fields need setting, not just the
password — I had omitted `installer-url` from the operator instructions. password — I had omitted `installer-url` from the operator instructions.
---
## 2026-09-18 — INCIDENT (mine): I printed the console password to the transcript
**What happened.** Verifying that the `unifi-uos-installer` Secret had reached the cluster, I ran a
`kubectl get secret -o jsonpath` that included `{range .data}{@}{end}`. That dumps the whole `data`
map, so the base64 of `console-password` was printed to the session transcript. This is precisely the
constraint I have written into every agent brief in this repo — *never print decrypted secrets* — and I
broke it myself with a careless jsonpath while checking someone else's work.
**Exposure, stated precisely rather than minimised or inflated:**
- The value reached the session transcript, which I cannot scrub.
- It did **not** reach git: `git log --all -S<value>` returns **0 commits**.
- The scratch file that captured it (`tasks/*.output`) was shredded; a repo- and scratch-wide grep for
the string now returns nothing on disk.
**Why it is not yet a working credential — the one thing that limits this.** The Secret was created
`2026-09-14T07:26:43Z`; the running VMI was created `2026-09-12T20:48:30Z`, and its live volume list is
only `rootdisk` and `cloudinit` — **the `UOSDATA` disk is not attached to the running VMI at all**. So
the guest has never read the Secret, `install-uos` has never executed, and the `ubuntu` account remains
locked. The leaked string authenticates nothing today. It would only become valid when the VMI is
recreated against the new spec.
**Required action, and the ordering matters:** rotate `console-password` in the SOPS Secret **before**
recreating the VMI. Then the leaked value never becomes a working password anywhere:
sops apps/vms/unifi/unifi-uos-installer.sops.yaml # set a NEW console-password
git commit && git push # let Flux update the Secret
kubectl -n unifi delete vmi unifi # only after the rotation has landed
**The lesson, generalised.** Reading a Secret to check *existence* never requires reading its
*values*. `-o jsonpath='{.metadata.name}'` or listing `.data`'s KEYS answers "did it land?"; dumping
`.data` answers a question nobody asked. Every previous secret check in this session used a
keys-only or boolean form — this one regressed because I appended a convenience field to an
otherwise-safe command without re-reading what it expanded to.