Skip to content

Security

This page describes ShipSquares’ security architecture, threat model, and hardening guidance.

If you discover a security vulnerability, please report it privately — do not open a public issue. Contact the maintainers directly or use the project’s security advisory feature.

Internet (untrusted: webhooks, browsers, API clients)
│ HTTPS only
Caddy (reverse proxy) — auto-HTTPS via ACME, on-demand TLS for custom domains
│ localhost
Control plane (Node/TS) — session + API-key auth, RBAC per route, audit log,
│ sealed secrets (AES-256-GCM)
├── PostgreSQL (job queue, sealed secrets, audit trail)
└── Docker socket / SSH → deployed apps, managed DBs, worker servers
  • Sessions — secure, HttpOnly cookies, SameSite=Strict.
  • API keysss_live_* bearer tokens, SHA-256 hashed before storage.
  • 2FA / TOTP — optional per-user two-factor.
  • SSO — OAuth with GitHub / Google when configured.
  • Passkeys — WebAuthn support.

Four roles with decreasing privilege:

RoleCapabilities
ownerFull access: org settings, member management
adminApp/server management, secrets, deploys — no org admin
deployerDeploy, view logs, restart apps — no secrets or server access
viewerRead-only access to apps, logs, metrics

API keys default to the deployer role and can be scoped to specific permissions.

  • At rest: AES-256-GCM with a master key (SHIPSQUARES_MASTER_KEY, 256-bit).
  • Sealed values are stored as {iv, ciphertext, tag, version} and resolved only at deploy time — never logged; values are masked in logs.
  • SSH keys are platform-generated Ed25519 keypairs with the private half sealed.
  • Every resource query is scoped by organizationId.
  • Cross-tenant access returns 404 (not 403) to avoid leaking existence.
  • API keys are org-scoped; sessions track the active org and verify membership per request.
ThreatMitigation
Credential theftSecrets encrypted at rest, never logged; SSH keys sealed
Session hijackingHttpOnly + SameSite cookies; HTTPS enforced
CSRFSameSite=Strict; API uses bearer tokens
XSSCSP headers; framework auto-escaping; no inline scripts
SQL injectionORM with parameterized queries
SSRFDatabase Studio validates hostnames against private ranges
Webhook spoofingHMAC (SHA-256) signature verification

Trust assumption: as with every Docker-based PaaS, the control plane holds access to the host Docker socket (root-equivalent). Protect the control-plane host and the master key accordingly.

  • Generate a strong master key (openssl rand -hex 32) and set it via the environment.
  • Run the control plane as a non-root user with a least-privilege Postgres role.
  • Allow only 80/443 inbound; restrict SSH.
  • Set ALLOW_SIGNUP=false after initial setup and invite members instead.
  • Require 2FA for admin/owner, and configure SSO for org login.
  • Review the built-in audit log periodically.