docs(security): prove the delivery path on hardware; close window 15
Controlled test on archi-dev-box with operator approval. The daemon was
stopped first so the reconciler could not repair the state before the
re-exposure was confirmed — without a confirmed 200, the later 401 would
be consistent with the state never having been broken at all.
1. stale conf installed + container restarted -> POST /bitcoin-rpc/
returned 200 with a real block height and Allow-Origin: *
2. daemon started 20:00:36, nothing else touched
3. 20:02:19 reconcile rendered the conf and logged the expected warn
line naming bitcoin-ui/archy-bitcoin-ui, then restarted it
4. POST -> 401, Allow-Origin origin-scoped
5. conf byte-identical to the pre-test known-good, container healthy
Both halves are now proven on real hardware: a05956c4's template (the
gate works) and f6b5245b's delivery path (the gate reaches a container
the reconciler had been skipping).
Also records the operator's decision AGAINST credential rotation — no
macaroon, no Bitcoin RPC password — with the trade it accepts stated
plainly, so it is not silently re-litigated later.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
186a2c36c8
commit
e205f2c34a
+10
-6
@@ -170,13 +170,17 @@ Stopped at: Phase 10 complete; a05956c4 verified on archi-dev-box, delivery gap
|
||||
Resume file: docs/security/BITCOIN-RPC-PROXY-EXPOSURE.md
|
||||
|
||||
Open on this thread (all recorded as broken windows, none blocking):
|
||||
- Window 15: f6b5245b's reconcile path is deployed but NEVER EXERCISED — an unrelated
|
||||
bitcoin-ui rebuild cleared the stale state before the fix landed. Needs a node whose
|
||||
bitcoin-ui conf is still stale, or a deliberately re-staled one.
|
||||
- Window 15 CLOSED 2026-08-02 20:02 — f6b5245b's reconcile path proven on archi-dev-box by
|
||||
a controlled test: stale conf installed + container restarted (probe 200, genuinely
|
||||
re-exposed), daemon started, reconcile repaired it unaided at 20:02:19 with the expected
|
||||
warn line, probe 401, conf byte-identical to the known-good. Both halves now proven on
|
||||
hardware.
|
||||
- Windows 11/12: host-secret rotation on three fleet nodes sharing SSH host keys —
|
||||
detect-only so far; rotation is USER-GATED and deliberately not actioned.
|
||||
- LND macaroon + Bitcoin RPC password rotation: scripts/ordering understood, NOT run on
|
||||
any node per explicit user instruction 2026-08-02. A general "rotate credentials later"
|
||||
path is wanted and unbuilt.
|
||||
- Credential rotation DECIDED AGAINST 2026-08-02 (operator): no LND macaroon rotation, no
|
||||
Bitcoin RPC password rotation — no evidence of exploitation and the vulnerability is
|
||||
being closed rather than lived with. rotate-lnd-macaroon.sh stays as a tool, exercised in
|
||||
detect mode only, never run against a node. Do not re-litigate; see
|
||||
docs/security/BITCOIN-RPC-PROXY-EXPOSURE.md.
|
||||
- archy-x250-dev has been offline 2 days, so every "dev pair" verification this session
|
||||
reached one node, not two.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
schema_version: 1
|
||||
open_count: 12
|
||||
open_count: 11
|
||||
waived_count: 0
|
||||
fixed_count: 3
|
||||
fixed_count: 4
|
||||
total_count: 15
|
||||
last_updated: 2026-08-02T23:16:04.510Z
|
||||
last_updated: 2026-08-03T00:06:03.112Z
|
||||
---
|
||||
|
||||
# Broken Windows Ledger
|
||||
@@ -29,7 +29,7 @@ last_updated: 2026-08-02T23:16:04.510Z
|
||||
| 12 | 10 | unrun-verify | scripts/security/host-secrets-audit.sh | | Rotation never exercised on real hardware: that 'systemctl reload ssh' keeps the operator's own forked session alive is proven only by design, not by observation. Needs --apply --yes on one disposable node from a session the operator is willing to lose. | open | | 2026-08-02T19:07:40.217Z | |
|
||||
| 13 | 10 | unrun-verify | core/archipelago/src/api/rpc/system/handlers.rs | | system.stats host_secrets never observed on a real node — proven against the file contract in unit tests only. Needs a build carrying 10-04 deployed to the dev pair, then a system.stats call. | fixed | | 2026-08-02T19:07:40.522Z | 2026-08-02T23:00:30.894Z |
|
||||
| 14 | 10 | unrun-verify | core/archipelago/src/container/prod_orchestrator.rs | | LIVE EXPOSURE on archi-dev-box: archy-bitcoin-ui (systemd/Quadlet-owned, user-uninstalled marker set) still serves unauthenticated POST /bitcoin-rpc/ on 0.0.0.0:8334 with Access-Control-Allow-Origin *, reaching Bitcoin Core RPC through a credential-injecting proxy. Verified live 2026-08-02 (returned a real block height with no cookies). Code fix committed f6b5245b but NOT deployed: closing it needs the new binary on the node plus an archy-bitcoin-ui restart. archy-electrs-ui is in the same uninstalled-but-running state (static UI only, no credential proxy). Operator-gated; no node touched. | fixed | | 2026-08-02T22:44:15.215Z | 2026-08-02T23:16:04.071Z |
|
||||
| 15 | 10 | unrun-verify | core/archipelago/src/container/prod_orchestrator.rs | | The f6b5245b reconcile fix is DEPLOYED on archi-dev-box (binary installed 19:06, running) but NEVER EXERCISED on hardware: the state it repairs (uninstall marker + Quadlet-running + stale config) stopped existing here at 18:36, when a separate rebuild of bitcoin-ui rendered the fixed conf and restarted the container. So :8334 returning 401 proves a05956c4's template, NOT the reconcile path that is supposed to deliver it. archy-electrs-ui still carries the marker+running shape and could exercise it, but has no rendered config to rewrite. Needs a node that still has a stale bitcoin-ui conf, or a deliberately re-staled one. | open | | 2026-08-02T23:16:04.510Z | |
|
||||
| 15 | 10 | unrun-verify | core/archipelago/src/container/prod_orchestrator.rs | | The f6b5245b reconcile fix is DEPLOYED on archi-dev-box (binary installed 19:06, running) but NEVER EXERCISED on hardware: the state it repairs (uninstall marker + Quadlet-running + stale config) stopped existing here at 18:36, when a separate rebuild of bitcoin-ui rendered the fixed conf and restarted the container. So :8334 returning 401 proves a05956c4's template, NOT the reconcile path that is supposed to deliver it. archy-electrs-ui still carries the marker+running shape and could exercise it, but has no rendered config to rewrite. Needs a node that still has a stale bitcoin-ui conf, or a deliberately re-staled one. | fixed | | 2026-08-02T23:16:04.510Z | 2026-08-03T00:06:03.112Z |
|
||||
|
||||
````json
|
||||
[
|
||||
@@ -208,10 +208,10 @@ last_updated: 2026-08-02T23:16:04.510Z
|
||||
"file": "core/archipelago/src/container/prod_orchestrator.rs",
|
||||
"line": null,
|
||||
"description": "The f6b5245b reconcile fix is DEPLOYED on archi-dev-box (binary installed 19:06, running) but NEVER EXERCISED on hardware: the state it repairs (uninstall marker + Quadlet-running + stale config) stopped existing here at 18:36, when a separate rebuild of bitcoin-ui rendered the fixed conf and restarted the container. So :8334 returning 401 proves a05956c4's template, NOT the reconcile path that is supposed to deliver it. archy-electrs-ui still carries the marker+running shape and could exercise it, but has no rendered config to rewrite. Needs a node that still has a stale bitcoin-ui conf, or a deliberately re-staled one.",
|
||||
"status": "open",
|
||||
"status": "fixed",
|
||||
"reason": "",
|
||||
"recorded_at": "2026-08-02T23:16:04.510Z",
|
||||
"resolved_at": null
|
||||
"resolved_at": "2026-08-03T00:06:03.112Z"
|
||||
}
|
||||
]
|
||||
````
|
||||
|
||||
@@ -100,8 +100,48 @@ rounded off: `bitcoin-ui` is *still* in the node's `user-uninstalled` marker, me
|
||||
next time its config needs to change, this node depends on `f6b5245b` — untested — or on
|
||||
someone happening to rebuild the app again.
|
||||
|
||||
Tracked as broken window 15. Closing it needs a node whose `bitcoin-ui` conf is still
|
||||
stale, or a deliberately re-staled one.
|
||||
Tracked as broken window 15 — **since closed by the controlled test below.**
|
||||
|
||||
## Proving the delivery path on real hardware
|
||||
|
||||
Run on archi-dev-box, 2026-08-02 20:00–20:03 EDT, with operator approval. The point was to
|
||||
prove the thing the incidental rebuild had made unprovable: that **reconcile itself**
|
||||
repairs this state, unaided.
|
||||
|
||||
The daemon was stopped first, so the reconciler could not repair the state before the
|
||||
re-exposure had been confirmed — otherwise a passing probe would prove nothing about
|
||||
which mechanism produced it.
|
||||
|
||||
| Step | Action | Observed |
|
||||
|---|---|---|
|
||||
| 1 | Install a faithfully stale conf (no `auth_request`, credential-injecting `proxy_pass`, `Allow-Origin: *`) and restart the container | — |
|
||||
| 2 | Probe with no cookies | `POST /bitcoin-rpc/` → **`200`**, `{"result":960790}`; `Allow-Origin: *`. **Genuinely re-exposed** |
|
||||
| 3 | Start the daemon (20:00:36) and touch nothing further | — |
|
||||
| 4 | Reconcile pass at **20:02:19** | `bitcoin_ui: nginx.conf rendered auth_hash=51f2b5af`, then `WARN prod_orchestrator: rewrote config for a user-uninstalled app whose container is still RUNNING (systemd/Quadlet keeps it alive independently of reconcile) — restarting so it picks the new config up app_id=bitcoin-ui container=archy-bitcoin-ui` |
|
||||
| 5 | Probe again | `POST /bitcoin-rpc/` → **`401`**; `Allow-Origin: http://192.168.63.240:8334` |
|
||||
| 6 | Compare state | Conf **byte-identical** to the pre-test known-good; container healthy |
|
||||
|
||||
Step 2 is what makes steps 4–6 mean anything: without a confirmed `200`, the later `401`
|
||||
would be consistent with the state never having been broken at all.
|
||||
|
||||
Both halves are now proven on hardware: `a05956c4`'s template (the gate works) and
|
||||
`f6b5245b`'s delivery path (the gate arrives at a container the reconciler had been
|
||||
skipping).
|
||||
|
||||
## Credential rotation — decided against, 2026-08-02
|
||||
|
||||
The operator's call, recorded here so it is not silently re-litigated: **no LND macaroon
|
||||
rotation, and no Bitcoin RPC password rotation.** The reasoning was that there is no
|
||||
evidence of exploitation and the vulnerability is being closed rather than lived with.
|
||||
|
||||
`scripts/security/rotate-lnd-macaroon.sh` stays in the tree as a tool. It has been
|
||||
exercised in detect mode only, and has never rotated anything on any node. Its ordering
|
||||
guard (refuses to rotate on a binary lacking the fix) remains the right shape for whenever
|
||||
rotation is wanted — including for the Bitcoin RPC password, which has no equivalent tool
|
||||
yet.
|
||||
|
||||
What this decision accepts: any macaroon or RPC password read through either hole before
|
||||
it was closed stays valid. That is a deliberate, informed trade, not an oversight.
|
||||
|
||||
## Operator note
|
||||
|
||||
|
||||
Reference in New Issue
Block a user