diff --git a/documentation/audits/evidence-bignight-2026-09-14/journal.md b/documentation/audits/evidence-bignight-2026-09-14/journal.md index 92acda89..b366430f 100644 --- a/documentation/audits/evidence-bignight-2026-09-14/journal.md +++ b/documentation/audits/evidence-bignight-2026-09-14/journal.md @@ -332,3 +332,11 @@ originals**. Attachment: the v2 slot's returned `url` is `/ciphers//attachme The retried attachment downloads 200 with its recorded size; byte-equality not proven (harness lost the key). **Finding R-512 (P2):** registration stays open and the page's instruction to close it points at a read-only field; a stranger registered with no invite (200). + +### SECURITY — R-513 (P1), found 18:30Z while looking for a way to put a video on the drive + +The launcher's **Filebrowser** tile opens `files.enkicsifelhom.hu`: password login, no signup. **No screen gives the +customer a FileBrowser login.** A customer's first guess, `admin` / `admin`, **works** (200 + token); wrong password +401. With it, both sources list (Adatlemez → `documents`, …; Beolvasás → `paperless`). The same login works on demo-hp's +**9201** and **9202**, and 9201's login page answers **200 through Cloudflare from the internet** (GET only, no login +attempted remotely). Filed R-513 before anything else; nothing changed on any box. diff --git a/documentation/audits/evidence-bignight-2026-09-14/phase3/deploy-jellyfin.txt b/documentation/audits/evidence-bignight-2026-09-14/phase3/deploy-jellyfin.txt new file mode 100644 index 00000000..d1ccca0a --- /dev/null +++ b/documentation/audits/evidence-bignight-2026-09-14/phase3/deploy-jellyfin.txt @@ -0,0 +1,10 @@ + select HDD_PATH: options=['Adatlemez — 92.0 GB szabad (alapértelmezett)'] -> /mnt/felhom-drives/hdd_1 +jellyfin: fields ['HDD_PATH', 'SUBDOMAIN']; secrets in /tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/a23ddbf6-6c9b-4b80-8fa9-69a2a962eeb6/scratchpad/apps/jellyfin.json: [] +POST 18:29:34 + -> {"ok":true,"message":"Telepítés elindítva – az állapot a kártyán követhető"} + + +5s not_deployed + +10s deploying + +40s starting + +50s running +jellyfin: final running after 50s diff --git a/documentation/audits/evidence-bignight-2026-09-14/phase3/deploy-paperless-ngx.txt b/documentation/audits/evidence-bignight-2026-09-14/phase3/deploy-paperless-ngx.txt index c5b184c3..93e24606 100644 --- a/documentation/audits/evidence-bignight-2026-09-14/phase3/deploy-paperless-ngx.txt +++ b/documentation/audits/evidence-bignight-2026-09-14/phase3/deploy-paperless-ngx.txt @@ -7,3 +7,5 @@ POST 18:26:12 +5s not_deployed +10s deploying +81s starting + +182s running +paperless-ngx: final running after 182s diff --git a/documentation/audits/evidence-bignight-2026-09-14/phase3/filebrowser-login-probe.txt b/documentation/audits/evidence-bignight-2026-09-14/phase3/filebrowser-login-probe.txt new file mode 100644 index 00000000..cc0e74fc --- /dev/null +++ b/documentation/audits/evidence-bignight-2026-09-14/phase3/filebrowser-login-probe.txt @@ -0,0 +1,10 @@ +18:30:10 launcher tile -> files.enkicsifelhom.hu; login page: passwordAvailable True, signup False, noAuth False +try admin/admin (what a customer would guess) -> 200 +18:30:38 negative control admin/ -> 401 {"status":401,"message":"user unauthorized"} +admin/admin -> 200 +self 401 {'username': None, 'perm': None, 'permissions': None, 'scopes': None} +list Adatlemez 401 [] [] +list Beolvasás 401 [] [] +VM333 auth via bearer users/self 200 {"editorQuickSave":false,"hideSidebarFileActions":false,"disableQuickToggles":false,"disableSearchOptions":false,"deleteWithoutConfirming":false,"preview":{"dis + list Adatlemez 200 {"name":"hdd_1","size":45056,"modified":"2026-09-14T20:12:59.031117756+02:00","type":"directory","hidden":false,"hasPreview":false,"folders":[{"name":"documents","size":4096,"modified":"2026-09-14T20:12:59.028945995+02:0 + list Beolvasás 200 {"name":"beolvasas","size":4096,"modified":"2026-09-14T20:26:13.419412334+02:00","type":"directory","hidden":false,"hasPreview":false,"folders":[{"name":"paperless","size":4096,"modified":"2026-09-14T20:28:54.364385439+0 diff --git a/documentation/audits/evidence-bignight-2026-09-14/phase3/filebrowser-public-reachability-demo-hp.txt b/documentation/audits/evidence-bignight-2026-09-14/phase3/filebrowser-public-reachability-demo-hp.txt new file mode 100644 index 00000000..b6a021a9 --- /dev/null +++ b/documentation/audits/evidence-bignight-2026-09-14/phase3/filebrowser-public-reachability-demo-hp.txt @@ -0,0 +1,7 @@ +=== public reachability of demo-hp's Filebrowser login page, GET only, from DooPlex via Cloudflare 2026-09-14T18:31:13Z +172.67.130.252 104.21.3.175 +GET https://files.enkisfelhom.hu/ -> 200 server=cloudflare +"noAuth":false +"passwordAvailable":true +FileBrowser Quantum +(no login was attempted over the internet) diff --git a/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-immich.txt b/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-immich.txt index 34e058e2..2be71fa1 100644 --- a/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-immich.txt +++ b/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-immich.txt @@ -7,3 +7,11 @@ 18:26:39 jobs pending {'faceDetection': (2, 194), 'smartSearch': (2, 181), 'ocr': (1, 197)} 18:27:09 jobs pending {'faceDetection': (2, 188), 'smartSearch': (2, 163), 'ocr': (1, 193)} 18:27:39 jobs pending {'faceDetection': (2, 182), 'smartSearch': (2, 144), 'ocr': (1, 189)} +18:28:09 jobs pending {'faceDetection': (2, 168), 'smartSearch': (2, 115), 'ocr': (1, 183)} +18:28:39 jobs pending {'faceDetection': (2, 147), 'smartSearch': (2, 74), 'ocr': (1, 173)} +18:29:09 jobs pending {'faceDetection': (2, 118), 'smartSearch': (2, 21), 'ocr': (1, 162)} +18:29:39 jobs pending {'faceDetection': (2, 68), 'ocr': (1, 140)} +18:30:09 jobs pending {'faceDetection': (2, 40), 'ocr': (1, 129)} +18:30:39 jobs pending {'faceDetection': (2, 16), 'ocr': (1, 118)} +18:31:09 jobs pending {'ocr': (1, 94)} +18:31:39 jobs pending {'ocr': (1, 57)} diff --git a/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-jellyfin.txt b/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-jellyfin.txt new file mode 100644 index 00000000..5ed035a3 --- /dev/null +++ b/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-jellyfin.txt @@ -0,0 +1,13 @@ +18:31:37 public info 200 {"LocalAddress":"http://172.18.0.14:8096","ServerName":"bdfc2285e7e5","Version":"10.11.11","ProductName":"Jellyfin Server","OperatingSystem":"","Id":"343cb9311f +18:31:37 wizard /Startup/Configuration 204 +18:31:38 wizard /Startup/User 200 +18:31:38 wizard /Startup/User 204 +18:31:38 wizard /Startup/RemoteAccess 204 +18:31:38 wizard /Startup/Complete 204 +18:31:40 login 200 +18:31:40 libraries before 200 [] +18:31:40 dir browser 200 {} +18:31:40 drives 200 ['/', '/cache', '/config', '/media'] +18:31:40 dir /media 200 ['/media/audiobooks', '/media/books', '/media/comics', '/media/movies', '/media/music', '/media/photos', '/media/podcasts', '/media/tv'] +18:31:40 dir /data 404 +18:31:40 dir /mnt 200 [] diff --git a/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-paperless.txt b/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-paperless.txt new file mode 100644 index 00000000..980e2d1a --- /dev/null +++ b/documentation/audits/evidence-bignight-2026-09-14/phase3/seed-paperless.txt @@ -0,0 +1,35 @@ +18:29:52 token (generated admin) 200 +18:29:52 tag Számla 201 +18:29:52 tag Garancia 201 +18:29:52 tag Adó 201 +18:29:57 posted 20 documents +18:29:57 tasks {'PENDING': 18, 'STARTED': 2} +18:30:07 tasks {'PENDING': 18, 'STARTED': 2} +18:30:17 tasks {'PENDING': 14, 'STARTED': 2, 'FAILURE': 4} +18:30:28 tasks {'PENDING': 14, 'STARTED': 2, 'FAILURE': 4} +18:30:38 tasks {'PENDING': 12, 'STARTED': 2, 'FAILURE': 6} +18:30:48 tasks {'PENDING': 12, 'STARTED': 2, 'FAILURE': 6} +18:30:58 tasks {'PENDING': 10, 'STARTED': 2, 'FAILURE': 8} +Traceback (most recent call last): + File "/usr/lib/python3/dist-packages/requests/models.py", line 963, in json + return complexjson.loads(self.content.decode(encoding), **kwargs) + ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/lib/python3.13/json/__init__.py", line 346, in loads + return _default_decoder.decode(s) + ~~~~~~~~~~~~~~~~~~~~~~~^^^ + File "/usr/lib/python3.13/json/decoder.py", line 345, in decode + obj, end = self.raw_decode(s, idx=_w(s, 0).end()) + ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/lib/python3.13/json/decoder.py", line 363, in raw_decode + raise JSONDecodeError("Expecting value", s, err.value) from None +json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/a23ddbf6-6c9b-4b80-8fa9-69a2a962eeb6/scratchpad/seed_paperless.py", line 21, in + r=s.get(B+'/api/tasks/',headers=H); st=[t.get('status') for t in r.json() if t.get('task_id') in tasks] + ~~~~~~^^ + File "/usr/lib/python3/dist-packages/requests/models.py", line 971, in json + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) +requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0) diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md index e220b339..a20e8245 100644 --- a/documentation/backlog/OPEN-ITEMS.md +++ b/documentation/backlog/OPEN-ITEMS.md @@ -716,6 +716,7 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server` | **R-510** | **[P1-HIGH] `tester-1`'s tunnel now has its route, and still gives a fresh box 502: the route sends traffic to `https://traefik` WITH certificate checking, and traefik answers the name `traefik` with its default certificate.** MEASURED 2026-09-14 (BIGNIGHT, VM 333, ISO 1.27.1, controller 0.242.0), after the operator's R-505 fix: from DooPlex `https://felhom.enkicsifelhom.hu` → **502 ×3** (18:07:48Z, `server: cloudflare`). The box's `cloudflared` logs `Request failed … tls: failed to verify certificate: x509: certificate is valid for 544346c4….traefik.default, not traefik … ingressRule=0 originService=https://traefik`. Traefik itself holds a valid Let's Encrypt `CN=*.enkicsifelhom.hu` (openssl on 127.0.0.1:443 with SNI). **Control:** demo-hp's working tunnel config reads `{"hostname":"*.enkisfelhom.hu", "originRequest":{"noTLSVerify":true}, "service":"https://traefik"}` — the same route WITH `noTLSVerify`. So the Cloudflare-side public hostname for `*.enkicsifelhom.hu` lacks „No TLS Verify" (or an origin server name). The Cloudflare side is not visible to the session; the inference rests on the log line and the control. Intervention **I2** of the big night: the claim and every dashboard request go to the guest's LAN address with the name forced. **Fix:** operator ticks „No TLS Verify" on that public hostname, then day-0 A.1 names the setting beside the route. | **WAITING-ON-OPERATOR — rank P1-HIGH; owner: operator (Cloudflare route), CC (day-0 A.1 wording after)** | | **R-511** | **[P2-MEDIUM] A customer whose box is rebuilt keeps its ep0 PBS token, and then the DR tier can be neither provisioned nor re-issued: the hub's error advises the one action that refuses.** MEASURED 2026-09-14 (BIGNIGHT, VM 333, `tester-1`, DR tier ticked): on the new box's WireGuard registration the hub logged `[ERROR] pbsdr auto-provision for tester-1 (WG-registration hook): the endpoint already holds a PBS token for tester-1 but the hub has no descriptor — use the explicit "Re-issue PBS credentials" action — save the customer config to retry`. The operator's `POST /configs/tester-1/pbsdr-reissue` → **400 `No provisioned PBS DR tier for this customer`** (`hub/internal/web/pbsdr.go` ~411). The token was left by the doorstep walk's host delete (a host delete does not deprovision tenancy; only RESET does, which also removes the tunnel). So a box rebuilt for an existing customer — the reinstall journey — has no whole-guest off-site tier and no button that restores it. **Fix shape:** let re-issue adopt an existing endpoint token when the descriptor is absent (the message already assumes it does), or have host delete offer to drop the PBS token. | **READY — rank P2-MEDIUM; owner: CC (hub)** | | **R-512** | **[P2-MEDIUM] Vaultwarden is installed with open registration, and the one control the page tells the customer to use to close it is read-only.** MEASURED 2026-09-14 (BIGNIGHT, VM 333, controller 0.242.0, catalog vaultwarden 1.36.0-alpine): the deploy form sends `SIGNUPS_ALLOWED=true` (catalog default); after install, „Vaultwarden — Beállítások" says „Ez az alkalmazás már telepítve van. **Az alábbi beállítások csak olvashatók.**" and, below it, „Regisztráció engedélyezése — Igen / Nem — Új fiókok regisztrálásának engedélyezése. **Az első fiók létrehozása után állítsd 'Nem'-re.**" At 18:27:20Z a stranger with no invite and no login registered `idegen.probe@example.com` → **200** (`phase3/vaultwarden-stranger-signup.txt`). Once the dashboard is reachable through the tunnel, anyone who guesses `vault.` can open an account on the household's password server. A route does exist (the Vaultwarden admin panel's own setting, token under „Megjelenítés"), and no screen names it. **Fix shape:** default `SIGNUPS_ALLOWED=false` with an invite-first first step, or make that one field editable after install; the page must not instruct an act it forbids. | **READY — rank P2-MEDIUM; owner: CC (catalog + controller)** | +| **R-513** | **[P1-HIGH — SECURITY] Every box's file manager (FileBrowser, `files.`, a launcher tile) accepts the login `admin` / `admin`, and on demo-hp that login page is on the public internet.** MEASURED 2026-09-14 (BIGNIGHT): `POST /api/auth/login?username=admin` with `X-Password: admin` → **200 + a session token** on VM 333 (fresh ISO 1.27.1 install, controller 0.242.0) and on demo-hp guests **9201 and 9202** (loopback, `Host: files.enkisfelhom.hu`); negative control `admin` / wrong → **401** on all three. On VM 333 that token lists both sources — „Adatlemez" (the data drive's `userdata`: documents, media, photos…) and „Beolvasás" (with `paperless`) — `GET /api/users?id=self` 200. **Public exposure, measured by GET only:** `https://files.enkisfelhom.hu/` from DooPlex through Cloudflare → 200, FileBrowser Quantum, `passwordAvailable:true, noAuth:false` (`phase3/filebrowser-public-reachability-demo-hp.txt`); no login was attempted over the internet. The generated `config.yaml` sets no admin credential (FileBrowser's own default applies); no screen shows the customer any FileBrowser login. Geo-restriction narrows who can reach it, it does not authenticate. **Not changed tonight** (9201's standing state is fenced; no product code). **Fix shape:** the controller sets a generated admin password (or proxy auth behind the dashboard session) at stack creation and on every existing box, and shows it where the customer finds app credentials. | **READY — rank P1-HIGH; owner: CC (controller) · operator (rotate on live boxes first)** |