-
-
Notifications
You must be signed in to change notification settings - Fork 43
Security Model and Hardening
WebSSH is a privileged gateway: it receives SSH credentials, opens remote sessions, processes terminal data, and transfers files. HTTPS protects browser traffic in transit, but WebSSH itself necessarily sees the material needed to perform those operations. It is not end-to-end encrypted between the browser and the SSH server.
Protect all of the following as sensitive systems:
- the WebSSH host and container runtime;
-
DATA_DIR, its backups, and the persistedSECRET_KEY; - the reverse proxy and TLS private keys;
- LDAP bind, OIDC client, Redis, and other infrastructure credentials;
- administrator browsers and accounts;
- networks from WebSSH to SSH, LDAP, OIDC, Redis, and DNS endpoints.
A compromise of the WebSSH process or its host can expose active terminal/file data and credentials supplied to it.
WebSSH includes:
- CSRF protection for HTTP forms and authenticated Socket.IO event contracts;
-
HttpOnly,SameSite=Laxsession cookies andSecurecookies in production; - Content Security Policy, HSTS in production, frame denial, MIME sniffing prevention, referrer policy, and permissions policy;
- per-user ownership checks for sessions, transfers, files, profiles, keys, and host-key data;
- bounded connection, transfer, temporary-storage, and background-work quotas;
- login, reauthentication, connection, backup, and default rate limits;
- explicit SSH target policy and per-user host-key verification;
- encrypted private-key storage derived per user;
- security audit logging and administrator reauthentication;
- bounded maintenance, shutdown, backup, and restore workflows.
These are defense layers, not a reason to expose a default homelab configuration directly to the Internet.
For Internet exposure:
- Use
docker-compose.production.ymlin addition to the base Compose file. - Terminate modern HTTPS at a maintained reverse proxy.
- Bind WebSSH to loopback or a private network, not a public interface.
- Set exact HTTPS
CORS_ORIGINS; never use a wildcard. - Set
TRUSTED_PROXIESto the exact number of trusted proxy layers. - Keep
SESSION_COOKIE_SECURE=true. - Disable public registration and browser admin bootstrap.
- Confirm that production's mandatory internal-target blocking matches the intended SSH target network.
- Use Redis-backed rate limiting when counters must survive restarts.
- Protect and test backups, recovery codes, and the local administrator path.
Stored SSH private keys are encrypted with Fernet. The per-user encryption material is derived using PBKDF2-HMAC-SHA256 with 600,000 iterations from SECRET_KEY:user_id. This reduces exposure from a copied data directory alone, but it does not protect keys from a running, fully compromised application that also has the secret.
Prefer scoped remote accounts, least privilege, short-lived credentials where possible, and SSH server-side restrictions. Never write passwords, tokens, or private-key contents to logs.
WebSSH uses a per-user known-hosts store and trust-on-first-use workflow. A newly trusted key is pinned. A changed key is rejected until the discrepancy is independently investigated and the old trust record is explicitly revoked.
Do not train users to accept changed keys as routine. Validate the remote host's fingerprint through a separate channel.
- LDAP: use
ldaps://or StartTLS, validate the server certificate, use a read-only least-privileged service account, and restrict user/group filters. - OIDC: use a trusted issuer, exact redirect URIs, a secret file, and explicit domain or subject policy where required.
- Passkeys: keep recovery codes offline and revoke lost authenticators promptly.
- Tailscale SSH: use tight WebSSH-user, target, and remote-user allowlists; the node identity is shared.
LDAP/AD authentication does not copy directory passwords into WebSSH and does not automatically create local accounts. Authentication is denied unless a local account and explicit directory link already exist.
The SQLite database, user JSON files, known-host data, notes, profiles, commands, and encrypted keys live in DATA_DIR. Native backups may also contain the persisted SECRET_KEY, making them sufficient to decrypt stored key material. Encrypt backups separately and restrict access and retention.
Do not disclose suspected vulnerabilities in a public issue. Follow the private reporting channels in the repository's SECURITY.md, such as a GitHub private security advisory or the listed security contact.
Before exposure, verify effective configuration rather than the intended .env alone:
docker compose \
-f docker-compose.yml \
-f docker-compose.production.yml \
configThen confirm HTTPS redirects, secure cookies, origin rejection, proxy IP handling, registration state, SSH target policy, host-key behavior, rate limiting, /ready, backup download expiry, and restore maintenance behavior.
WebSSH documentation - Project - Issues - Discussions - Security
WebSSH Wiki
Install and operate
- Installation from Source
- Docker and Docker Compose
- Production Deployment
- Reverse Proxy and Subfolder Deployment
- Upgrading, Rollback, and FAQ
Identity and access
- Users and Account Management
- Authentication Overview
- LDAP and Active Directory
- OpenID Connect
- Passkeys and Recovery Codes
SSH and files
- SSH Connections and Host Keys
- Profiles, Jump Hosts, and Commands
- Terminal and Persistent tmux Sessions
- SFTP File Workspace and Transfers
- Tailscale SSH
Reference and administration