gates / gates (push) Successful in 12m37s
Read-only audit of whether the hacked Plex pod on DooPlex (HM-040, 2026-10-17 -> 10-23) reached Felhom's secrets. Two no-login doors existed (the Longhorn NFS export and the Longhorn API); neither was used: nfsd accepted 0 new connections in the window (positive control), no off-schedule Longhorn backup or volume. Evidence in documentation/audits/plex2shell-felhom-impact-2026-10-23/. The NFS export was narrowed from * to 10.42.0.0/16 on the operator's yes (host change, not in git). 13-threat-model.md: attacker j and one boundary row. STATUS: verdict, the P1, one do item.
76 lines
5.5 KiB
Markdown
76 lines
5.5 KiB
Markdown
# REPORT — did the Plex attack on DooPlex reach Felhom's secrets? (2026-10-23)
|
|
|
|
## Plain words first
|
|
|
|
1. **Verdict: NOT REACHED.** Two open doors led from the hacked Plex to Felhom's secrets. Neither was used in the attack
|
|
days: the backup folder got no new connection at all, and Longhorn made no backup or disk outside its normal plan.
|
|
2. **The shared backup folder: closed to the home network and the tailnet** (your yes). It is **still open to every app
|
|
on DooPlex** — Longhorn needs that, so the real fix is the homelab session's.
|
|
3. **What you do next:** give the homelab session the hand-over list (`documentation/audits/plex2shell-felhom-impact-2026-10-23/README.md`,
|
|
last section). Nothing needs to be rotated.
|
|
|
|
## The Part 4 table
|
|
|
|
In `documentation/audits/plex2shell-felhom-impact-2026-10-23/README.md` § Part 4. Short form: every Felhom secret on
|
|
DooPlex has exposure **none**. The ones a hacked pod *could* have reached: the hub's unencrypted nightly copies (with the
|
|
unsealed Cloudflare/tunnel/git tokens, R-975) through the NFS export or a Longhorn backup, and the operator signing keys
|
|
through the NFS file-handle escape (documented, not exercised). Sealed hub columns need a key that is not in the copies;
|
|
escrow blobs need each household's recovery code; the k8s API, the kubelet and the hub refuse a caller with no credential
|
|
(measured).
|
|
|
|
## The paths and the evidence per path
|
|
|
|
| path | existed? | evidence of use (window 10-17 04:00Z → 10-23 08:04Z) |
|
|
|---|---|---|
|
|
| NFS export `longhorn-pvc` (`*`, `no_root_squash`, `no_subtree_check`; `secure` void in pods) | yes | **unused** — `node_nfsd_connections_total` flat at 288 for 13 days, 3902 samples, no gap; positive control: today's three probe connections moved it to 4. nfsd is TCP-only. Reads only in Longhorn's backup hours |
|
|
| Longhorn API :9500, no login | yes | **no sign of use** — 0 backups first seen off-schedule (1-min scrape); every night wrote to the local store; no unexplained volume; the backup target is the 2025-11-29 one. Manager logs: lost (reboot) |
|
|
| hub `hub:8080` direct | yes, but no secret without a credential | 0 requests from 10.42.0.52 in `/data/access-log` (from 10-18 10:25Z; positive control: the probe's IP is logged). 10-17 04:00Z → 10-18 10:25Z: no record |
|
|
| k8s API, kubelet | no (401) | — |
|
|
| SSH, Samba on DooPlex | login needed | 0 sshd lines from the pod network (control: 61 from the LAN); no Samba client file for 10.42.0.52 (positive control: the probe made one) |
|
|
| Vaultwarden | login needed; vault encrypted | logs lost (reboot) |
|
|
|
|
**Evidence lost before this session started:** the 13:20Z maintenance reboot erased the pre-reboot container logs of
|
|
longhorn-manager, longhorn-ui, the ingress, the hub, Gitea, Vaultwarden, Grafana and Prometheus. Reproduced
|
|
independently from records that survived: Prometheus history (nfsd, Longhorn, cAdvisor, node network), the hub's own
|
|
access log, the journal (boot -1), Samba per-client files, CoreDNS error lines, the Alertmanager silence list. The
|
|
incident session's pre-reboot greps (10.42.0.52 in longhorn-manager, CNPG, Gitea, authentik: 0) are cited as theirs.
|
|
|
|
## For the homelab session
|
|
|
|
The seven items at the end of the audit README: the export still open to pods (and `secure` is void there); Longhorn API
|
|
and UI with no login; an unattributed Longhorn delete of the old Plex volume at 11:24:15Z; **~1.5 TB sent out by the Plex
|
|
pod 10-18 → 10-22** (not in INCIDENT.md) plus `hand.genddos.st` DNS lookups on 10-19; the reboot that erased the logs;
|
|
the monitoring stack and Headlamp reachable from every pod; a `python3 main.py` listener on :8443. No HM numbers minted;
|
|
`homelab-manifests` not touched.
|
|
|
|
## What this session changed
|
|
|
|
- **DooPlex `/etc/exports`** (operator yes, ~15:18Z): `longhorn-pvc` from `*` to `10.42.0.0/16`, `exportfs -ra`; Longhorn
|
|
target `available: true` at 15:20:10Z. Backup `/etc/exports.bak-2026-10-23-plex2shell`. The only change on DooPlex.
|
|
- **Probe pod** `default/cc-p2s-probe`: created 15:19:46Z, removed 15:33:44Z; before/after listings in the evidence. No
|
|
other object created. The incident's NetworkPolicies untouched.
|
|
- **felhom.eu:** the audit folder; R-1241 and R-1242 in `OPEN-ITEMS.md`; `13-threat-model.md` (attacker j, one boundary
|
|
row); `STATUS.md` (verdict in „What works", the P1 in „What is broken", one „do" item; the old „Updated" paragraph moved to
|
|
`STATUS-HISTORY.md`).
|
|
- Nothing rotated. No secret value written anywhere (evidence scanned for secret shapes; the only 64-hex string is the
|
|
sha256 of `/etc/exports`).
|
|
|
|
## Rows
|
|
|
|
Before 186, after 188; opened 2 (R-1241 P1, R-1242 P3), closed 0.
|
|
|
|
## Observations
|
|
|
|
- Hacked pod → hub backups + signing keys through the NFS export and the Longhorn API — FILED: R-1241.
|
|
- Demo NAS export on the same disk with `no_subtree_check` — FILED: R-1242.
|
|
- The hub answers pods without the geo filter — NOT-A-FINDING: the geo filter is not authentication; every no-token path refused.
|
|
- demo-felhom's Proxmox UI and SSH reachable from any DooPlex pod — NOT-A-FINDING: the door of R-982; added as attacker j in `13` §3.
|
|
- Pod logs erased by the reboot — NOT-A-FINDING for Felhom (the hub's access log persisted, R-1140); handed to the homelab session.
|
|
|
|
## Notes for the next session
|
|
|
|
- Teardown, three layers: machine — probe pod removed, export change kept on purpose (operator yes); host — none; hub —
|
|
none (read-only access-log aggregation in the running pod).
|
|
- System poster: no fact on it changed (none of the three applied).
|
|
- `unproven.py`: not run — no capability claim changed.
|