Termi
Back to home

Security Policy

How Termi protects your data, and how to report a vulnerability responsibly.

Last updated: June 6, 2026

On this page

  • Reporting a vulnerability
  • Supported versions
  • Scope
  • Security architecture
  • Encryption
  • Authentication
  • Connection security
  • Application hardening
  • Operator responsibilities
  • Disclosure policy

Reporting a vulnerability

We take the security of Termi seriously. If you believe you have found a security vulnerability, please report it to us privately — do not open a public GitHub issue, discussion, or pull request for it.

  • Preferred: use GitHub's private vulnerability reporting to open a security advisory.
  • Alternatively: email shuvo.punam@gmail.com with the details.

To help us triage quickly, please include:

  • A description of the vulnerability and its potential impact.
  • Steps to reproduce, including a proof of concept where possible.
  • The affected version, commit, or deployment configuration.
  • Any suggested remediation, if you have one.

We aim to acknowledge reports within 72 hours and to provide a remediation timeline after triage. Please give us a reasonable opportunity to address the issue before any public disclosure.

Supported versions

Termi is distributed as source. Security fixes are applied to the main branch, and we recommend running the latest released version. Older versions do not receive backported security patches.

Scope

The following are in scope for a vulnerability report:

  • Authentication and session management flaws.
  • Credential encryption or key-handling weaknesses.
  • Server-Side Request Forgery (SSRF) and injection vulnerabilities.
  • Privilege escalation or broken access control between users.
  • Flaws in the WebSocket gateway or JWE token handling.

Issues that are generally out of scope include findings that require a compromised host, missing best-practice headers without a demonstrable impact, vulnerabilities in your own self-hosted misconfiguration, and reports from automated scanners without a working proof of concept.

Security architecture

Termi runs as two independently deployable services plus a remote-desktop daemon:

  • Web app — the Next.js application, REST API, and credential store. It is the only component that can decrypt stored credentials.
  • Gateway — a WebSocket service that proxies SSH, SCP, RDP, and VNC traffic. It never has standing access to plaintext credentials; it receives them only inside a short-lived signed token at connection time.
  • guacd — the Apache Guacamole daemon used for RDP/VNC, reachable only from the gateway.

This separation means the internet-facing gateway holds no long-lived secrets, limiting the blast radius if it is compromised.

Encryption

  • Credentials at rest — every host, username, password, privateKey, passphrase, and notes field is encrypted with AES-256-GCM before storage. Plaintext is never written to these fields.
  • Optional master key — users can add a second encryption layer derived from a personal master key via PBKDF2, so credentials cannot be decrypted without it even with full database access.
  • Key management — encryption keys are supplied through environment variables (ENCRYPTION_KEY) and are never stored in the database alongside the data they protect.

Authentication

  • Password hashing — account passwords are hashed with Argon2id using secure parameters.
  • Two-factor authentication — TOTP-based 2FA is supported (Google Authenticator, Authy, and compatible apps), with recovery codes.
  • Sessions — managed with encrypted, HTTP-only iron-session cookies on a 7-day lifetime.

Connection security

Credentials are decrypted only at the moment of connection and are never exposed to the browser:

  • The web server issues a 5-minute JWE token (A256GCM) containing the decrypted connection details.
  • The browser opens a WebSocket to the gateway using that token; the gateway validates it and brokers the SSH/SCP/RDP/VNC session.
  • Tokens are single-purpose and short-lived, minimizing the window in which a leaked token is useful.

Application hardening

  • SSRF protection — every user-supplied host is validated before a connection is attempted, blocking access to internal and link-local address ranges.
  • Content Security Policy — a strict, per-request nonce-based CSP and a full set of security headers are applied to every response.
  • Input validation — all API routes validate request bodies with schema validation before processing.

Operator responsibilities

Because Termi is self-hosted, a secure deployment is a shared responsibility. As an operator you should:

  • Generate strong, unique secrets for SESSION_SECRET, ENCRYPTION_KEY, and GATEWAY_JWT_SECRET (for example, with openssl rand -base64 32).
  • Serve the application strictly over HTTPS/TLS.
  • Keep your database, guacd, and host operating system patched.
  • Restrict network access to the gateway and guacd to trusted sources.
  • Back up your database and store secrets outside of version control.

Disclosure policy

We follow a coordinated disclosure model. After a fix is released, we will publish a security advisory crediting the reporter (unless anonymity is requested). We do not currently operate a paid bug-bounty program, but we deeply appreciate responsible disclosure and will gladly acknowledge your contribution.

Termi•MIT License
PrivacySecurityGitHub