From 57c58ebffb03959c6fc8bbb90d7500376e29394d Mon Sep 17 00:00:00 2001 From: Mitchell-Johnson Date: Fri, 18 Sep 2026 17:34:55 -0700 Subject: [PATCH] Bug bash 2026-09-18: findings list (discovery only) Co-Authored-By: Claude Fable 5.1 --- BUGS.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 BUGS.md diff --git a/BUGS.md b/BUGS.md new file mode 100644 index 0000000..4679882 --- /dev/null +++ b/BUGS.md @@ -0,0 +1,113 @@ +# Bug bash — 2026-09-18 + +Discovery only; nothing here is fixed yet. Found by a headless Chromium pass (iPhone and +1440px desktop viewports) over every page on the hub and on each remote machine, an +offline-node scenario (wyse stopped for the test, then restarted), direct API probing +with hostile inputs, and a code read. Ordered by severity within each group. + +## Security / robustness + +1. **Reading a special file hangs the request forever.** `GET /api/files/read?path=/dev/zero` + never ends: the `max` cap compares against `stat` size, which is 0 for device files, + so the cap never triggers and the handler streams `/dev/zero` until the client gives + up. Same for FIFOs (blocks on open) and `/proc/self/mem`. Opening one in the Files + viewer would hang the tab. Needs: refuse non-regular files for read/edit, and cap the + copy with `io.LimitReader` regardless of `stat`. +2. **Login lockout is global, not per client.** Five bad passwords from anyone on the + internet lock the real user out for up to 10 minutes (`auth.Limiter` is one bucket). + The bash locked the hub for the full 10 minutes twice. Also locks `POST /api/tokens`, + so hub pairing fails during a lockout. Needs per-IP buckets with a modest global cap. +3. **UI prefs from the server are not validated.** A stored `refreshMs` of `-5` made the + client call `setInterval(-5)` on every live view: a request storm that took the + browser to `ERR_INSUFFICIENT_RESOURCES` and hammered the daemon. `theme` is validated + only by falling back. Needs range checks on load (and on save server-side). +4. **No anti-framing / CSP headers.** Only HSTS (from NPM). A root-capable console should + send `X-Frame-Options: DENY`, `Content-Security-Policy: frame-ancestors 'none'`, + `Referrer-Policy: no-referrer`, `X-Content-Type-Options: nosniff` on every response. +5. **Signals can be sent to kernel threads.** `POST /api/procs/2/signal` (kthreadd) + returns 204. Harmless in practice, but the guard should refuse PIDs with an empty + cmdline (kernel threads) and our own PID. +6. **Journal spam from the daemon's own sudo calls.** Every sudo'd `journalctl`, `smartctl` + or `pwrstat` writes three `pam_unix(sudo:session)` lines into the journal *under + `hamlab.service`*: 839 lines in 10 minutes at a 250 ms refresh, and the journal is + already 4 GB. It also buries Ham Lab's own log entries. Fix options: add the service + user to `systemd-journal` (and `adm`) so journal reads don't need sudo, and/or a + sudoers `Defaults!/usr/bin/journalctl !syslog, !pam_session` line in the installer. +7. **Uploading over an existing file silently overwrites it.** No confirmation, no + "replace?" prompt. Same for "+ file" when the name exists (server refuses; UI just + shows the error, fine) — upload is the gap. +8. **`/api//../../x` falls through to the SPA** and returns `index.html` with + 200 instead of a JSON 404. Harmless, but sloppy for an API prefix. + +## Functional bugs + +9. **Wrong password gives no feedback at all.** The 401 is thrown as `Unauthenticated` + with an empty message, and the login form only renders `err` when non-empty. The + button just re-enables. Reproduced on phone and desktop. +10. **Switching machines while on Settings or Machines keeps showing the hub's page.** + `switchMachine` only resets the view for Machines; Settings stays, so "mac" shows + core's account/token/about panels. Both are hub-only pages and should bounce to the + dashboard (or be clearly labelled as hub pages). +11. **Machines add-form `pattern` is an invalid regex in Chromium.** `[a-z0-9][a-z0-9-]*` + fails under the `v` flag ("Invalid character class"), logs a console error and the + browser skips validation. Needs `[a-z0-9][a-z0-9\-]*`. +12. **Updates tab on dnf hosts shows nonsense.** Mac: "Index refreshed 561d ago" (mtime of + `/var/cache/dnf`, which Fedora 41+ no longer uses; `libdnf5` is the live cache) and + "Last upgrade never · from apt history" (label and source are apt-specific). Needs + `dnf history` for last upgrade, metadata timestamps for refresh, and neutral labels. +13. **Cron overview is slow: 3.6 s per request on core.** At any refresh rate the page + is constantly busy. The 30-day, 20 000-line journal scan for "last run" is rebuilt + every 5 s; timers make three `systemctl` calls. Needs an incremental journal cursor + and a single `systemctl` call. Services list is 0.6 s for the same reason (two calls). +14. **Daemon memory grows.** RSS on core went 22 → 85 → 216 MB during the day (136 MB at + rest after the bash). Suspects: per-pid caches in the process table (`procInfo` only + prunes on the next walk), task output buffers, SMART cache, xterm scrollback rings + that are never freed for exited sessions. Needs a heap profile under load. +15. **Version string is always `-dirty`.** `make deploy` builds before the commit, so + every installed binary reports e.g. `v0.1.0-32-ga372378-dirty`, and the Machines page + compares with `-dirty` stripped. Build after commit, or tag releases. +16. **View resets to Dashboard on reload; no deep links; browser Back leaves the app.** + The selected machine survives a reload (sessionStorage) but the tab does not, and + there is no URL routing at all. Needs hash or path routing (`/#/grid/services`). +17. **Cron log tab lists oldest first and starts at the top.** 200 lines from Sep 10 with + the newest at the bottom, off-screen. Should show newest first or scroll to the end. +18. **Processes: empty filter result shows nothing.** No "nothing matches" message. +19. **Terminals accumulate.** Nothing ever reaps exited or idle sessions; the bash left + several "bug-bash-term" shells on the hub until deleted by hand. Exited sessions + should auto-remove after a while; idle ones at least be counted somewhere. +20. **Self-update restarts without warning running work.** A push to a node kills its + open terminals and any running task (upgrade in progress). The hub should refuse or + warn when the node reports a running task or attached terminals. +21. **Error text leaks raw Go errors.** e.g. rename shows "rename /tmp/x /tmp/y: no such + file or directory". Fine for a lab, ugly for a product; strip the syscall prefix. + +## Mobile / UX + +22. **Tap targets under 28 px on phone:** header ⏻ (25), logout (22), customize ▲ ▼ hide + (23), terminal leaf ✎ ✕ (24), chips (25), table headers (27). Apple's guideline is + 44 pt. Systemic: the small `.btn`/`.chip`/`.icon-btn` sizes need a touch variant. +23. **Power dialog on the Mac asks you to type `5ce91ee54af6`.** The confirmation uses + the node's hostname, which on the Mac is the unset default. Should offer the machine + name (`mac`) as the confirmation word on remote machines. +24. **Dashboard shows dead interfaces and empty modules.** wlp1s0 (down) gets a full + sparkline block of flat lines; "Fans: no fan sensors" is a permanent empty card on + hosts without fans. Down interfaces should collapse to one line; empty modules should + auto-hide unless customizing. +25. **Header load average is unlabelled** ("1.39 1.56 1.55" floating in the header). +26. **Files list on desktop is a narrow strip in a sea of empty space** for small + folders; the row menu opens off the right edge of the row. Cosmetic. +27. **Offline machine keeps polling every view at the refresh rate**, producing a 502 + per request per page (and console errors). The UI copes — badge, message — but the + hub should back off to the prober's cadence while a node is down. +28. **Services logs are noise.** The default view of `hamlab.service` logs is the sudo + session spam from bug 6, three lines per poll. + +## Confirmed working under abuse (for the record) + +Path traversal in files, services, cron, ZFS, procs and updates all rejected. `/etc` +and `/` protected from delete/rename as root. Unit, pool, dataset, snapshot and +package names validated. Token issue refused with a wrong password. Oversized prefs +rejected. Duplicate machine add refused. Unicode + spaces in file names round-trip. +Upload byte-exact. Terminal scrollback survives switching. Offline node: switcher and +header show it, pages show the reason. Remote terminals, logs, tasks and files through +the proxy all work on all three nodes.