Repository navigation
v0.1.35 — security hardening + performance
Security hardening (external review batch)
A round of independent review surfaced six issues; all are fixed here.
- Session tokens now actually expire.
ValidSessionreturned the map-hit
instead of the expiry result, so an expired token was admitted one last time
(and the UI's 5s poll kept sliding live sessions' own expiry). Expired tokens
are now rejected and deleted in one pass. - Stored XSS via sensor name closed (two layers). A crafted sensor name
could escape its string context in inline event handlers. The UI now escapes
at the JS level for everyonclicksink, and the API rejects names
containing quotes/angle brackets/backticks/backslashes/control chars or over
60 characters on create and rename (400). - Login: per-IP failure throttle + timing-oracle close. 7 failed logins
from one IP in 60s → 5-minute lockout (429 +Retry-After), enforced before
any bcrypt work; a success clears the counter. The unknown-user dummy hash's
cost is now derived from the configured bcrypt cost so it can't drift, and
every rejected login pays a constant 200ms slowdown — capping online
password guessing at ~5 tries/second/IP. No per-account lockout: a typo'd
password can never lock the operator out. - All request bodies bounded to 1 MiB. The auth gate now wraps every
request body withhttp.MaxBytesReader; oversized bodies get a clean 413
instead of being streamed into the JSON decoder. GET /api/events?n=capped at 500, matching the sensor-history endpoint
(previously unbounded).POST /api/settings/testrejects unknown/missing provider kinds with 400
naming the valid kinds, instead of answering 200{"ok":false}.
Performance
Enabled()no longer hits the database on every request. The "is auth
enabled" check ranSELECT COUNT(*) FROM userson every request, including
the dashboard's 5s poll. It's now memoized for 2s; in-app user changes
(add/remove/disable) refresh it immediately, so the dashboard is never stale
and out-of-band CLI user management is picked up within 2s.
Polish
- The sensor form's Timeout field now explains that the pre-resolve DNS
lookup has its own 5s cap, so timeouts under ~6s don't bound DNS. - Corrupt sensor rows (which shouldn't happen with the app-controlled schema)
are now logged instead of silently vanishing from the fleet view. RemoveAllUsersnaming, andtsNow()used at every writer-side timestamp
site.
Full test suite passes under -race.