Skip to content
Galley

Security

Threat model.

Container-level isolation between previews. Encrypted secrets at rest. No VM-grade isolation. If your threat model assumes hostile PR code, read the limits below before turning Galley loose on it.

In scope

What Galley protects against.

  • Cross-preview reach. Each preview gets its own Docker network and named volumes. A container in preview A can't see preview B.
  • Cross-project secret leakage. Secrets are scoped per project. Encrypted at rest with a master key the operator controls.
  • Build-time privilege. Dockerfile builds run in disposable, unprivileged sandboxes with no daemon socket and the worktree mounted read-only. The autodetect path runs against an unprivileged build engine — no rootful daemon either way.
  • Webhook spoofing. GitHub deliveries are HMAC-verified. A failed signature is rejected and logged.
  • SSRF from previews. Outbound HTTP from the control plane (image pulls, webhook posts) blocks RFC1918, link-local, and the cloud metadata endpoint.
  • Audit gaps. Every admin action lands in an audit log with actor, target, IP, timestamp.
  • Stolen agent tokens. Agent bootstrap tokens are SHA-256 hashed in storage and have an expiry; rotation is one click.
Out of scope

What Galley does not protect against.

The isolation boundary is the Linux container. That's enough for trusted code on a shared host; it isn't enough for arbitrary code from external contributors.

  • Container escape. A kernel or runtime CVE that escapes the container also escapes Galley. Don't expose previews of untrusted code to the public internet.
  • Side channels between co-tenant previews. Co-tenancy is container-level, not hardware-level. Spectre-class attacks aren't mitigated.
  • Resource exhaustion. Quotas help but aren't hard walls. A preview that wants to degrade its neighbours can.
  • Outbound exfiltration from inside a preview. If the preview has a secret, code in the preview can post it wherever the network reaches. Scope secrets per-project, not globally.
  • Drive-by PRs from external contributors. Treating those PRs as hostile is the right default. Galley's v1 isolation doesn't materially change that — VM-grade isolation via Firecracker microVMs was on the design doc and isn't in v1.
Secrets

How secrets work.

Project-scoped secrets are encrypted at rest with AES-256-GCM. The encryption key is wrapped under a master key supplied at install via GALLEY_MASTER_KEY (32 random bytes, hex or base64). The master key never enters the database, never phones home, has no recovery.

The agent decrypts at deploy time and renders secrets as environment variables on the container. A tmpfs-mounted file option for apps that read secrets from disk is roadmap.

External secret managers — Vault, AWS/GCP/Azure, 1Password, Doppler — are roadmap. Today Galley owns the storage.

Isolation

Containers, not microVMs.

Standard Linux container isolation: namespaces, cgroups, a restrictive seccomp profile on build workers, no host mounts visible to user code, no rootful containers in the build path. Build sandboxes are disposable and run unprivileged.

That's enough when the code under build is from teammates. It's not enough when the code is from a stranger. Firecracker microVM isolation for the hostile-PR case is not in v1.

Disclosure

Reporting vulnerabilities.

Email utibeabasiumanah6@gmail.com with description, repro, and your preferred contact. GPG key available on request.

Acknowledged within one business day. 90-day disclosure starts on acknowledgement. Public credit in the release notes once a fix lands, if you want it. No bounty program yet.