Skip to content

Security Model

SSH private keys, GitHub tokens, and managed .env file contents are all encrypted with AES-256-GCM using CONVEYOR_ENCRYPTION_KEY, a single instance-wide key you generate at install time. See Installation for generating it and Backups for why it must be backed up separately from the database. Losing it makes every encrypted value permanently unrecoverable, even with an intact database.

A project’s .env also has its own bcrypt-hashed password gating UI access, independent of the encryption key. See Environment Files for exactly what that password does and doesn’t protect.

  • User passwords are hashed with bcrypt (cost 12).
  • Login checks a hash even for unknown email addresses (a precomputed dummy hash), so failed logins for accounts that don’t exist take the same time as a wrong password for one that does.
  • Sessions use 32-byte crypto/rand tokens with HttpOnly cookies, so they can’t be read from JavaScript. The session TTL is CONVEYOR_SESSION_MAX_AGE (default 86400 seconds / 24 hours).

Failed logins are throttled per client IP: after 5 failed attempts within a 15-minute window, that IP is locked out from attempting another login for 15 minutes. A successful login clears the counter for that IP.

All state-changing requests (anything other than the public webhook/deploy-API endpoints and the WebSocket routes) are protected by CSRF tokens, checked on every POST/PUT/DELETE.

Each project gets its own 256-bit random tokens for its webhook and deploy-API URLs (/api/webhook/<token> and /api/deploy/<token>). These endpoints are intentionally not session-authenticated; the token in the URL is the credential, so treat those URLs as secrets. See Webhooks for the optional additional signature/secret verification available for GitHub, Gitea, Forgejo, and GitLab.

Conveyor holds SSH private keys, GitHub tokens, and decrypted .env contents in its database, and its UI has no built-in role separation: anyone who can log in can see and change all of it. Run it accordingly:

  • Put it on a private network or behind a VPN rather than exposing it directly to the public internet.
  • Enable TLS (either self-signed for a zero-dependency setup, or custom with a real certificate) rather than serving plain HTTP if it’s reachable over any untrusted network. See Configuration for the TLS modes.
  • Restrict who has login credentials; there’s no built-in concept of read-only or per-project users.
  • Keep CONVEYOR_ENCRYPTION_KEY and your database backups equally protected. Either one alone reveals nothing, but both together expose every stored secret.