diff --git a/documentation/audits/cloudflared-2026.10.3-2026-10-26/NOTES.md b/documentation/audits/cloudflared-2026.10.3-2026-10-26/NOTES.md new file mode 100644 index 00000000..acfe864c --- /dev/null +++ b/documentation/audits/cloudflared-2026.10.3-2026-10-26/NOTES.md @@ -0,0 +1,27 @@ +# cloudflared 2026.10.3 — the eMudhra notice (R-1300), 2026-10-26 evening + +**The notice.** Cloudflare, 2026-10-20 (blog „8 eMudhra certificates are compromised"): eight eMudhra (emSign) +intermediate CA keys were weak (recoverable from the public certificates; six TLS, two code-signing). cloudflared +before 2026.10.2 trusts them. Docker users take the fixed image. Cloudflare: „do not resolve these errors by disabling +verification". Release notes: 2026.10.2 = Go 1.27.3 + new distroless base (the trust store); 2026.10.3 = newer +debian base + Go bump. 2026.10.4 (2026-10-26, today) adds a metrics-endpoint allowlist (VULN-176088) — not taken: +under a day old, and the notice names 2026.10.3. + +**Image.** `cloudflare/cloudflared:2026.10.3` index digest +`sha256:faa8e0a1475f137c910be6025f43c8e4092fdd35461b31e19fd1390657a1ff39` (Docker Hub API and a pull on 9202 agree; +amd64 `sha256:c3f24df7…`); `--version` = `cloudflared version 2026.10.3 (built 2026-10-21-13:24 UTC)`. +(`part3-image-check.txt`) + +**Part 1 — the list.** Three boxes report to the hub (demo-felhom, demo-hp, Tester 1); each guest 9201 runs +`cloudflare/cloudflared:2026.9.3` (`part1-boxes.txt`, `part1-hub-hosts.txt`). 9202 (scratch) has no tunnel. Tester 2: no box. +DooPlex: no cloudflared in k3s, Docker, systemd, dpkg or processes; the same queries find traefik/the hub (control) +(`part1-dooplex.txt`). Cloudflare account: CC holds no Cloudflare token (`sec list`); the connector versions are the +operator's look in Networking → Tunnels. + +**Part 2 — the https-origin trap.** Every tunnel's remote route (cloudflared's own „Updated to new configuration" log +line, all three boxes): `*.` → `https://traefik`, `originRequest.noTLSVerify: true`, then `http_status:404` +(`part2-remote-config.txt`). traefik answers SNI `traefik` with `CN=TRAEFIK DEFAULT CERT`, self-signed +(`part2-origin-cert.txt`). No eMudhra chain → the new trust store refuses nothing on the origin leg: **the trap does +not apply.** The `noTLSVerify` is the day-0 recipe (R-510) for a leg that never leaves the guest (cloudflared and +traefik alone on the /29 `felhom-tunnel`); not changed tonight (the brief forbids touching certificate checks, and +turning verification ON needs traefik to present a cert cloudflared can verify — a design question, not tonight). diff --git a/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-boxes.txt b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-boxes.txt new file mode 100644 index 00000000..d304d736 --- /dev/null +++ b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-boxes.txt @@ -0,0 +1,26 @@ +== felhom-pve +demo-felhom +VMID Status Lock Name +9201 running demo-felhom +-- ct 9201 +felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.345.0 Up 6 hours (healthy) +cloudflared cloudflare/cloudflared:2026.9.3 Up 5 days (healthy) +== demo-hp +demo-hp +VMID Status Lock Name +9201 running demo-hp +9202 running demo-hp-scratch +9401 stopped upgrade-harness +-- ct 9201 +felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.345.0 Up 6 hours (healthy) +cloudflared cloudflare/cloudflared:2026.9.3 Up 3 days (healthy) +-- ct 9202 +felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.343.0 Up 2 hours (healthy) + 341 night1004-tester1 running 8192 200.00 1364274 +== root@192.168.0.154 +felhom +VMID Status Lock Name +9201 running tester-1 +-- ct 9201 +felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.345.0 Up 6 hours (healthy) +cloudflared cloudflare/cloudflared:2026.9.3 Up 2 days (healthy) diff --git a/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-dooplex.txt b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-dooplex.txt new file mode 100644 index 00000000..f912549c --- /dev/null +++ b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-dooplex.txt @@ -0,0 +1,15 @@ +== k3s pods +== k3s images any +== docker +== systemd +== dpkg +== processes +2667091 /bin/bash -c source /home/kisfenyo/.claude/shell-snapshots/snapshot-bash-1793042538348-zvqq4e.sh 2>/dev/null || true && shopt -u extglob 2>/dev/null || true && { \builtin unalias -- 'unsetenv' +2667092 /bin/bash -c source /home/kisfenyo/.claude/shell-snapshots/snapshot-bash-1793042538348-zvqq4e.sh 2>/dev/null || true && shopt -u extglob 2>/dev/null || true && { \builtin unalias -- 'unsetenv' +2667753 /bin/bash -c source /home/kisfenyo/.claude/shell-snapshots/snapshot-bash-1793042538348-zvqq4e.sh 2>/dev/null || true && shopt -u extglob 2>/dev/null || true && { \builtin unalias -- 'unsetenv' +== positive control: same queries find traefik/hub +1 +2 +1 +== docker images cached +== homelab-manifests mentions diff --git a/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-hub-hosts.txt b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-hub-hosts.txt new file mode 100644 index 00000000..1e4f3409 --- /dev/null +++ b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part1-hub-hosts.txt @@ -0,0 +1,4 @@ +Host | Customer | Agent | Proxmox / kernel | Status | Guests | CPU | Mem | Disk | Cloudflared | Worst Storage +demo-felhom-8363b5 | Demo Ügyfél | 0.166.0 floor: declared MinAgent | 9.2.21 7.0.14-25-pve | ONLINE | 1/2 | 0% | 20% | 35% | running (connected) | 35% local +demo-hp-bb76ea | Demo HP | 0.166.0 floor: declared MinAgent | 9.2.21 7.0.14-25-pve | ONLINE | 1/2 | 11% | 45% | 61% | running (connected) | 61% local +tester-1-d70be4 | Tester 1 | 0.166.0 floor: declared MinAgent | 9.2.2 7.0.14-22-pve | ONLINE | 1/2 | 7% | 33% | 27% | running (connected) | 27% local diff --git a/documentation/audits/cloudflared-2026.10.3-2026-10-26/part2-origin-cert.txt b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part2-origin-cert.txt new file mode 100644 index 00000000..6881b536 --- /dev/null +++ b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part2-origin-cert.txt @@ -0,0 +1,21 @@ +== felhom-pve +traefik=172.20.0.2 +/bin/openssl + 0 s:CN=TRAEFIK DEFAULT CERT + i:CN=TRAEFIK DEFAULT CERT +Verify return code: 18 (self-signed certificate) + Verify return code: 18 (self-signed certificate) +== demo-hp +traefik=172.26.0.2 +/bin/openssl + 0 s:CN=TRAEFIK DEFAULT CERT + i:CN=TRAEFIK DEFAULT CERT +Verify return code: 18 (self-signed certificate) + Verify return code: 18 (self-signed certificate) +== root@192.168.0.154 +traefik=172.22.0.2 +/bin/openssl + 0 s:CN=TRAEFIK DEFAULT CERT + i:CN=TRAEFIK DEFAULT CERT +Verify return code: 18 (self-signed certificate) + Verify return code: 18 (self-signed certificate) diff --git a/documentation/audits/cloudflared-2026.10.3-2026-10-26/part2-remote-config.txt b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part2-remote-config.txt new file mode 100644 index 00000000..bdac2ccd --- /dev/null +++ b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part2-remote-config.txt @@ -0,0 +1,18 @@ +== felhom-pve +2026-10-21T03:24:06Z INF Starting tunnel tunnelID=8b4edf48-1846-4484-870e-68b48cf43483 +2026-10-21T03:24:06Z INF Version 2026.9.3 (Checksum af73b73c18b1fe8c50293af01630a59789ddd9eb1edb56472fe5559b3a4a340c) +2026-10-21T03:24:06Z INF GOOS: linux, GOVersion: go1.26.8, GoArch: amd64 +2026-10-21T03:24:07Z INF Updated to new configuration config="{\"ingress\":[{\"hostname\":\"*.demo-felhom.eu\", \"originRequest\":{\"noTLSVerify\":true}, \"service\":\"https://traefik\"}, {\"service\":\"http_status:404\"}], \"warp-routing\":{\"enabled\":false}}" version=1 +cloudflared version 2026.9.3 (built 2026-09-24-16:19 UTC) +== demo-hp +2026-10-23T15:34:00Z INF Starting tunnel tunnelID=d7a3c848-d754-46ce-a1c1-ca6bc7a81775 +2026-10-23T15:34:00Z INF Version 2026.9.3 (Checksum af73b73c18b1fe8c50293af01630a59789ddd9eb1edb56472fe5559b3a4a340c) +2026-10-23T15:34:00Z INF GOOS: linux, GOVersion: go1.26.8, GoArch: amd64 +2026-10-23T15:34:01Z INF Updated to new configuration config="{\"ingress\":[{\"hostname\":\"*.enkisfelhom.hu\", \"originRequest\":{\"noTLSVerify\":true}, \"service\":\"https://traefik\"}, {\"service\":\"http_status:404\"}], \"warp-routing\":{\"enabled\":false}}" version=1 +cloudflared version 2026.9.3 (built 2026-09-24-16:19 UTC) +== root@192.168.0.154 +2026-10-24T17:47:21Z INF Starting tunnel tunnelID=52d0c214-b833-477c-86d8-f787d9b550dd +2026-10-24T17:47:21Z INF Version 2026.9.3 (Checksum af73b73c18b1fe8c50293af01630a59789ddd9eb1edb56472fe5559b3a4a340c) +2026-10-24T17:47:21Z INF GOOS: linux, GOVersion: go1.26.8, GoArch: amd64 +2026-10-24T17:47:22Z INF Updated to new configuration config="{\"ingress\":[{\"hostname\":\"*.enkicsifelhom.hu\", \"originRequest\":{\"noTLSVerify\":true}, \"service\":\"https://traefik\"}, {\"service\":\"http_status:404\"}], \"warp-routing\":{\"enabled\":false}}" version=2 +cloudflared version 2026.9.3 (built 2026-09-24-16:19 UTC) diff --git a/documentation/audits/cloudflared-2026.10.3-2026-10-26/part3-image-check.txt b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part3-image-check.txt new file mode 100644 index 00000000..ae48b3d3 --- /dev/null +++ b/documentation/audits/cloudflared-2026.10.3-2026-10-26/part3-image-check.txt @@ -0,0 +1,4 @@ +docker.io/cloudflare/cloudflared:2026.10.3 +cloudflare/cloudflared@sha256:faa8e0a1475f137c910be6025f43c8e4092fdd35461b31e19fd1390657a1ff39 2026-10-21T13:26:38.565206178Z +cloudflared version 2026.10.3 (built 2026-10-21-13:24 UTC) +removed diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md index a5b09f93..26458f87 100644 --- a/documentation/backlog/OPEN-ITEMS.md +++ b/documentation/backlog/OPEN-ITEMS.md @@ -231,10 +231,11 @@ stopping line that lies. | **R-1275** | Storage & devices | P4 | **An English household sees the drive names in Hungarian** on the install page (and wherever a storage label shows): „Belső tárhely — 52.0 GB free (default)”, „Külső tárhely (hdd_1)” (catalog sweep 2026-10-24, `audits/catalog-sweep-2026-10-24/navidrome/page-install-en.txt`). The label is stored once, in Hungarian, when the drive is found (`felhom-controller/controller/internal/settings/settings.go` `InferStorageLabel`); a household may rename it. | OPEN | — | Render a label that still equals the inferred default in the reader's language; a test per language | CC | | **R-1276** | Storage & devices | P4 | **„Remove with data” leaves the app's empty parent folder** (`/appdata/`) when the template binds a subfolder: Grimmory, RomM, Paperless-ngx (catalog sweep 2026-10-24; 4 KB each; the bound folders were removed). Harmless (empty, not counted as old data), untidy for a household that browses the drive. | OPEN | — | Remove the parent when it is empty after the bound folders go; a test | CC | -## Security & access — 24 rows (P1 2, P2 3, P3 13, P4 6) +## Security & access — 25 rows (P1 3, P2 3, P3 13, P4 6) | ID | Category | Sev | What | State | Blocked on | Next action | Owner | |---|---|---|---|---|---|---|---| +| **R-1300** | Security & access | P1 | **cloudflared on every box trusts eight eMudhra (emSign) intermediates with weak keys** (Cloudflare's notice 2026-10-20; fixed in 2026.10.2): someone with those keys could pose as any website to the tunnel. List 2026-10-26: three boxes report (demo-felhom, demo-hp, Tester 1), each guest 9201 on `cloudflare/cloudflared:2026.9.3`; none on DooPlex; Tester 2 has no box. Origin trap NOT-A-FINDING: every route is `https://traefik` with `noTLSVerify` (R-510) and traefik shows its self-signed default certificate. Fix: controller **v0.345.1** = v0.345.0 + `CloudflaredImage` `2026.10.3` (index `sha256:faa8e0a1…`); `main` carries it too. `audits/cloudflared-2026.10.3-2026-10-26/` | OPEN — filed 2026-10-26 (attended); closes when every box reports cloudflared 2026.10.3 | the global floor (operator yes) | build + per-box floor on the test boxes, then ask for the global floor | CC | | **R-1241** | Security & access | P1 | **2026-10-24: the Felhom half is DONE** — hub 0.168.0 deployed (the tokens sealed; every copy leaving the volume is clean, the live file's old bytes accepted by the operator, R-975 closed), the hub volume out of the Longhorn backup (D40, R-1243 VERIFY), the two old plain copies deleted by the operator. **What stays here is the homelab half:** the open NFS export and Longhorn's login (the homelab session). **A hacked app pod on DooPlex can read the hub's nightly database copies — with every customer's unsealed Cloudflare, tunnel and git token (R-975) — through the Longhorn NFS export, and by a published file-handle escape the operator signing keys on the same disk: whoever breaks one homelab app can take over the boxes' tunnels and sign agent updates.** MEASURED 2026-10-23 (Plex2Shell impact audit, `audits/plex2shell-felhom-impact-2026-10-23/`): export `/mnt/5_hdd/backup/longhorn-pvc` rw, `no_root_squash`, `no_subtree_check`, a sub-directory of sda1, which also holds `/mnt/5_hdd/felhom.eu/felhom-op-*` (no passphrase, R-924); `secure` is void in pods (containerd sets `ip_unprivileged_port_start=0`; a uid-1000 probe with no capabilities bound port 700); the four `felhom-system` volumes have `encrypted=false`; Longhorn's API on :9500 answers any pod with no login (backups, targets, volumes). In the Plex2Shell window neither door was used — verdict NOT REACHED (nfsd accepted 0 new connections 10-10 → 10-23, positive control; no off-schedule Longhorn backup or volume). 2026-10-23 ~15:18Z, operator yes: the export was narrowed from `*` to `10.42.0.0/16` — the home network and the tailnet are closed, pods are not (Longhorn connects from its pod address). Not exercised: the escape itself (Tier-2 machine). | OPEN | the homelab session (DooPlex host + cluster); the operator (R-924) | Homelab: a NetworkPolicy so only `longhorn-system` reaches :2049/:111 and :9500, or the backup store on its own filesystem. Felhom: R-975 sealed in hub 0.168.0 (deploy pending); the hub's plain Longhorn copies → R-1243; a passphrase on the signing keys (R-924) | operator | | **R-1139** | Security & access | P2 | **Tester 2's break-glass root password was not rotated with the others (R-954, operator decision D1 = A, 2026-10-17): the box has been offline since 2026-10-04.** demo-hp, Tester 1 and demo-felhom were rotated and proven on 2026-10-17 (`audits/agent-allowlist-rotation-2026-10-17/P3/`). | OPEN — filed 2026-10-17 **2026-10-22: closes when Tester 2 is reinstalled (operator ruling 2026-10-22 14:11 — a fresh install sets and vaults a new console password).** | Tester 2 reporting again | When it reports: the installer's step 4b alone (`P3/rotate-step4b.sh` shape), then the vaulted value logs in (PVE API 200) and the old one is refused | CC | | **R-1042** | Security & access | P3 | **The boxes' Cloudflare keys cannot change zone settings, so Cloudflare's own „Always Use HTTPS” cannot be switched on.** Measured 2026-10-14 on all three zones (`audits/https-only-2026-10-14/``1A-1-zones-and-keys.txt`): each `cf_api_token` is valid and sees only its own zone, but GET/PATCH `settings/always_use_https`, `ssl`, `security_header` answer 403; the redirect and transform rule phases too. The https-only fix therefore lives on the box (decision 246). A second layer at Cloudflare needs „Zone Settings: Edit” (and, for headers, „Transform Rules”) added to each customer's key — the hub's zone-reach check stays. | **WAITING-ON-OPERATOR** — filed 2026-10-14 | a key permission only the operator can grant | Optional: widen each customer key, then switch „Always Use HTTPS” on per zone | operator |