The one password
The browser/desktop login and SSH use the same Linux system password (accountclawbox). There is no separate admin or web password. Changing it anywhere changes it everywhere:
- Settings → System → Change password (web) — validated, rate-limited, applied via a privileged
chpasswdstep. sudo passwd clawbox(SSH) — takes effect for the browser immediately.- Factory reset — resets it to
clawbox.
Browser login flow
- The web app must resolve the right username —
CLAWBOX_USERenv →SUDO_USER→USER→ OS user, defaultclawbox. /usr/sbin/unix_chkpwdmust be setgidshadow(-rwxr-sr-x root shadow) — it’s the PAM helper that reads/etc/shadowon behalf of the non-root web app. SSH doesn’t need this (sshd is root), which is why SSH can work while the browser fails.- The running build must be current — a stale build from a half-finished update checks with old logic.
- The password bytes the browser sends must match — non-ASCII passwords can be encoded differently by the browser vs the terminal that set them.
Session cookies
clawbox_session is an HMAC-SHA256-signed expiry token (no server-side session store): base64url({exp}) + "." + HMAC(payload, secret). Durations: 20 min, 6 h, 12 h, or 24 h. The signing secret persists in data/.session-secret. Cookies are httpOnly, SameSite=Lax, and non-Secure (the LAN UI is plain HTTP).
Middleware enforces the cookie on every route except the public set (/login, /setup, static assets, captive-portal probes) — and skips enforcement entirely until first-boot setup completes.
Gateway token (machine, not human)
The OpenClaw gateway (port 18789) authenticates its WebSocket clients with a token stored atopenclaw.json → gateway.auth.token:
- Per-device random 32-byte hex — generated on first boot/reset and preserved thereafter. (Early builds shipped a public literal
"clawbox"; any such weak token is automatically rotated to a strong one on gateway start.) - The ClawBox UI injects this token into the OpenClaw Control UI automatically (via
/setup-api/gateway/ws-configand injected HTML) — users never type it. - The gateway service is started without
--tokenso the config value is the single source of truth. A stale service file that still passes--tokencauses the classicunauthorized: gateway token mismatcherror — fix withsudo bash install.sh --step gateway_setup.
Service-to-service tokens
All are per-install random values with
0600 permissions, seeded/re-hardened automatically at boot.
Provider credentials
AI provider keys and OAuth sessions are separate from all of the above — see AI Providers → Where credentials actually go for the full map.Security posture summary
- The gateway listens on the LAN but is token-gated (per-device random token); users go through the authenticated web app on port 80, which injects the token for them.
- A default-deny inbound firewall (ufw) ships on the device: only SSH (22), the web OS (80, and 443 when certs are installed at
data/certs/), the gateway (18789) and the Hermes dashboard proxy (8090) are reachable. On IPv4 that is further scoped to private LAN/Tailscale source ranges; IPv6 is not source-scoped — there is no RFC1918 equivalent and a normal dual-stack LAN hands the box a global address, which is exactly what avahi publishes forclawbox.local; on v6 the site router is the boundary. mDNS, plus DHCP and captive-portal DNS on the hotspot interface, stay open so discovery and the AP keep working. Everything else that happens to bind0.0.0.0(CUPS on 631, rpcbind on 111, the terminal PTY on 3006, Syncthing on 8384) is closed to the LAN. - Web login is rate-limited with lockout; passwords are never logged; control characters are rejected.
- Privileged operations run through an allowlisted systemd template (polkit + narrow sudoers), never arbitrary root exec from the web process.
- Telegram DMs default to pairing mode — unknown senders are inert until the owner approves their 8-character code. Config that would open DMs to everyone (
dmPolicy:"open"+allowFrom:["*"]) is actively stripped on boot. - On the Hermes edition the agent scans every shell command with
tirithbefore running it. The scanner is not shipped — the agent downloads it the first time the box is online — and upstream’s default is fail-open, so a box that has never had internet runs commands unscanned. Settings → System reports that state instead of leaving it silent, andsecurity.tirith_fail_open: falsein~/.hermes/config.yamlswitches the agent to refusing commands it cannot scan. - Factory reset wipes credentials, SSH keys, histories, and browser profiles — see Recovery.
- Vulnerability reports: see SECURITY.md.

