Skip to content

v0.9.8 — Security hardening pass

Choose a tag to compare

@brendan4linux brendan4linux released this 09 Jul 02:26
· 11 commits to main since this release
fa5b07a

v0.9.8 — Security hardening pass

This release is a comprehensive security hardening pass based on an adversarial peer code review. No new features — focus is entirely on closing injection, session, and authorization gaps.


🔴 Critical / High fixes

ID Issue Fix
H1 Command injection in APT/RPM repo key import (sh -c curl | gpg) Replaced with Go HTTP fetch + argv-only gpg --dearmor — no shell involved
H2 Firewall nftAdd fell back to sh -c on error, enabling injection via Port/Table/Chain fields Deleted sh -c fallback entirely; added strict regex validators for all nft inputs
H3 SSO bypass token accepted via ?token= URL param (logged by reverse proxies, browser history) Header-only (X-Webux-Token); comparison uses subtle.ConstantTimeCompare
H4 No rate limiting on /auth/login — online brute-force against PAM/shadow accounts Per-IP rate limiter: 10 failures per 15-minute window → HTTP 429
H5a Session cookie missing Secure flag Secure: true + SameSite: Strict
H5b JWT returned in login JSON body (invites localStorage storage, XSS-extractable) Token removed from response body; cookie-only delivery
H5c Logout was client-side only — leaked tokens stayed valid for 24h Server-side session store (webux_sessions table); each JWT carries a jti; logout deletes the row; every request verifies the session still exists
H6 MySQL USE \database`andSHOW TABLES IN `database`` used raw string interpolation Database name validated against ^[A-Za-z0-9_]+$ before any SQL construction
H7 Both WebSocket endpoints (/ws, /ws/terminal) accepted any Origin Origin validated against Host header on both upgraders
H8 No warning when JWT secret was auto-generated (silently breaks multi-instance deployments) Startup WARN log when ephemeral secret is used; directs operator to set auth.jwt_secret
H9 golang.org/x/net v0.21.0 — affected by CVE-2023-45288 (HTTP/2 CONTINUATION flood) Bumped to v0.56.0; x/crypto bumped to v0.53.0
H10 AI OllamaURL/BaseURL were user-settable and used directly in server-side HTTP — SSRF pivot Custom dial function blocks RFC-1918 and link-local ranges at connect time
C1 (partial) No authorization layer — any authenticated user got root; no audit trail Claims stored in request context; structured audit log on every authenticated request (user, method, path, ip); terminal now drops to the authenticated user's UID/GID/groups; auth.allowed_users config option restricts login to named accounts
C2 (partial) File manager safePath had no root restriction and was vulnerable to symlink escape EvalSymlinks + separator-aware prefix check; configurable files.root; sudo toggle for explicit root escalation

Other changes

  • File browser: removed artificial /home root restriction — OS permissions enforced naturally. Added per-request sudo mode (sudo -n) for browsing/editing root-owned files without running webux as root.
  • Terminal: shell now spawns as the Webux-authenticated user (SysProcAttr.Credential with UID/GID/supplementary groups resolved from the JWT subject).
  • Settings UI: bypass token hint updated to show X-Webux-Token header usage instead of deprecated ?token= param.
  • Router: fixed double /api/api/containers/run routing bug (L4).
  • Migration 009: webux_sessions table for server-side revocation.

Config additions (config.yaml)

auth:
  allowed_users:        # optional: restrict login to these Unix accounts
    - bdubs
    - ops

files:
  root: /home           # optional: restrict file browser root (default: unrestricted)

Upgrade notes

  • Breaking: the ?token=<bypass> query param no longer works — update any SSO redirects to send X-Webux-Token: <token> as a header instead.
  • Sessions issued before this upgrade will be invalidated on first request (missing jti in old tokens → treated as revoked). Users will need to log in once after upgrading.
  • The webux_sessions migration runs automatically on startup.

Thanks

Special thanks to John for the thorough adversarial security review that drove this entire release.