Skip to content

Security: sm26449/webterm

SECURITY.md

Security Policy

Reporting a vulnerability

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.

What is in scope

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.

What is NOT a vulnerability (by design)

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 webterm user; 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, the webterm-backup timer) are encrypted — AES-256-CBC with PBKDF2 via openssl enc, passphrase in /etc/default/webterm-backup, generated by install.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=1 is 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 insecure mode (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.

Supported versions

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.

Deployment best practices (read before exposing)

  • 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) and data/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 insecure mode in production.

There aren't any published security advisories