Do not open a public issue for security problems.
Report privately via GitHub Security Advisories: the Security tab → Report a vulnerability
(or .../security/advisories/new). You will get a private channel for discussion and a coordinated fix.
Include, if you can: the affected version, reproduction steps, the impact, and a proof of concept.
No GitHub account? Email stefan.maldaianu@gmail.com with WebTerm security in the subject.
Advisories are preferred — they give us a private thread and a coordinated fix — but not having an
account should never be the reason a problem goes unreported.
What to expect. The project is maintained by one person, in his spare time, so this is a promise about honesty rather than speed: an acknowledgement within 7 days, and an assessment (in scope or not, and roughly when) within 30 days. If you have not heard back in 30 days, assume the message was lost and ping again — that is a failure on my side, not impatience on yours. Fixes ship in the next release; you decide whether to be credited in the advisory.
Safe harbour. Test only against your own installation. Do not access other people's data, do not degrade a service someone else depends on, and give me a reasonable window before publishing. Within those limits I will not pursue anything against a good-faith report, and I would rather hear about a finding that turns out to be nothing than not hear about one that was real.
Bugs that break the documented trust boundaries (see docs/THREAT-MODEL.md):
- authentication / session / lockout bypass;
- Cross-Site WebSocket Hijacking, CSRF, XSS, injection (SQL/ANSI/OSC/header);
- path traversal, SSRF, secret leakage;
- accepting unsigned / downgraded agent updates, cert pinning bypass;
- forward isolation (token bound to slug), cross-host escalation.
WebTerm is designed for a single trusted administrator. The following are deliberate decisions, explained in docs/THREAT-MODEL.md, not bugs:
- The agent runs with its user's privileges on every host and never escalates; fs/command
operations are NOT sandboxed. Anyone who gets past login has that user's access across the whole
fleet — like holding an SSH key for it. The install command offered by default creates a dedicated
unprivileged
webtermuser; installing as the current user while root makes it root's. - Roles separate hosts, not people sharing a shell. Since 3.6.0 accounts have roles (Owner / Admin / Operator / Viewer over all hosts, a folder, a tag or one host — see docs/ROLES.md). They enforce which hosts an account can reach and whether it gets a shell there. Inside a host where an account holds a shell-equivalent permission it has the agent user's full power, and a shell on the host that runs WebTerm (or holds its backups) is equivalent to Owner. A role-check bypass — reaching a host outside your scope, getting a shell without a shell permission, or escalating your own role — is a vulnerability; please report it.
- The gateway is a single point of total compromise (it commands the agents). A compromised gateway = a compromised fleet.
- The gateway host holds the vault key, and so do its backups' secrets. Scheduled backups
(
scripts/backup.sh, thewebterm-backuptimer) are encrypted — AES-256-CBC with PBKDF2 viaopenssl enc, passphrase in/etc/default/webterm-backup, generated byinstall.sh— and a non-interactive run without a passphrase deletes the archive and exits 1 rather than write the vault key in cleartext (WEBTERM_BACKUP_ALLOW_PLAINTEXT=1is the explicit opt-out). The download from Settings → Backup uses a password of your choosing (scrypt → AES-GCM,WTBK1). The limitation is where the passphrase lives: on the same host as the data. Root on the gateway host can read every credential regardless of backup encryption — that is the premise above, not a weakness of the archive format. - The
insecuremode (TLS without validation) is an opt-in, documented footgun.
If you find a way to break one of these without the premises above (e.g. escalation from unauthenticated, or from one account to another's in a future multi-user setup), that is in scope — please report it.
Policy last reviewed: 2026-10-16 (3.6.15).
Actively developed; security fixes go into the latest version (main / the latest vX.Y.Z tag).
Run the most recent official image or build from main.
- Run with a domain + HTTPS + passkeys, not just IP/password.
- Install agents as a dedicated least-privilege user, not root, wherever you can.
- Your agent signing key is generated automatically on the first boot of an install with no
hosts (unencrypted, so auto-updates survive a restart); Settings → Infrastructure & tokens shows it. To use your
own or a passphrase-protected key instead, set it up before first boot or before enrolling
hosts: generate/import return 409 once a key exists, so you place
data/agent-signing.key(PEM, mode 600) anddata/agent-signing.pub(its public key, hex) yourself and restart the gateway. Swapping it after hosts are enrolled means reinstalling every agent (or the rollover in docs/design/SIGNED-UPDATES.md). - Do not expose
insecuremode in production.