ReaperCI threat model
This document covers the self-hosted ReaperCI hub, its embedded Git and OCI
services, BuildKit, direct-SSH targets, outbound connectors, and the public API.
The managed account and billing plane has a separate threat model in the private
reaperci-cloud repository. Revisit this model before every beta release and
whenever a trust boundary changes.
Security objectives
- Repository code may influence its own build, but must not control the hub, another repository, a protected environment, or a management host.
- Secrets are encrypted at rest, masked in build and deployment output, and disclosed only to the operation that needs them.
- Agents can inspect and request work, but cannot bypass human production approvals or act without an attributable service-account identity.
- A compromised managed edge cannot issue an unrestricted shell command to a customer VPS.
- Operators can identify who requested, approved, retried, promoted, rolled back, or changed a protected resource.
- Backups can restore the complete customer-owned data set without access to ReaperCI Cloud.
Assets
The highest-value assets are the instance master key, dashboard sessions, service-account and provider tokens, repository secrets, environment secrets, managed-server SSH keys, connector client keys, registry robot credentials, source repositories, built images and artifacts, deployment policy, audit history, and the integrity of production workloads.
The master key is deliberately outside the normal data volume. A data backup without its matching key cannot decrypt protected fields. Losing both the data and key backups is unrecoverable; disclosing both is a full confidentiality incident.
Trust boundaries
- Browser or API client to hub. HTTPS terminates at the operator-controlled edge. The hub authenticates a dashboard session or scoped bearer token and authorizes every resource operation.
- Provider to hub. GitHub, Gitea, Forgejo, and GitLab send signed webhooks. ReaperCI verifies the provider-specific signature before synchronizing a mirror or creating a build.
- Repository to BuildKit. Repository-controlled commands execute in BuildKit containers. BuildKit is on a private network, has explicit Linux platform and resource settings, and never receives the host Docker socket.
- Hub to embedded registry. A separate robot credential authorizes image push and pull. The hostname used by BuildKit must match the credential scope.
- Hub to direct-SSH server. Each server has a distinct encrypted private key. The first successful connection pins the host key; later mismatches fail closed.
- Hub to outbound connector. Enrollment uses a short-lived one-time token. All later traffic requires a client certificate over TLS 1.3. The connector polls outbound and accepts only typed operations granted at enrollment.
- Human or agent to protected environment. A service account may request a deployment, but only an authenticated human owner, admin, or operator can approve a protected environment.
Primary data flows
Git push/provider webhook
|
v
signed event -> mirror -> immutable build snapshot -> BuildKit
| |
| v
+-> commit status <- build result <- embedded registry
|
v
request -> policy -> human approval -> SSH/connector -> health check
|
v
live state / rollback / audit
Pull-request previews use the pipeline from the trusted base branch while building the untrusted head commit. The pull request therefore cannot redirect itself to production, replace its approval policy, or inject environment-scoped secrets.
Threats and controls
| Threat | Required controls | Verification |
|---|---|---|
| Credential theft from SQLite or backups | AES-256-GCM envelopes with context binding; master key mounted separately; no plaintext list APIs | migration tests, secret-store tests, restore drill |
| Session theft or CSRF | HttpOnly/SameSite cookies, secure cookies behind HTTPS, CSRF checks on browser mutations, session inventory and revocation | auth and browser acceptance tests |
| Token overreach | Expiring scoped service accounts and provider credentials; role checks on every public route | authorization matrix tests |
| Agent bypasses approval | Service-account identities are rejected at protected approval endpoints regardless of scopes | API and MCP approval tests |
| Malicious repository escapes build | isolated BuildKit, no host Docker socket, explicit Linux platforms, CPU/memory/time limits, bounded logs/artifacts | malicious-input and resource-enforcement tests |
| Pull request changes deployment policy | trusted-base pipeline; no environment secrets in previews; isolated names and Compose projects | preview integration tests |
| Webhook forgery or replay | provider signature verification, bounded payloads, durable delivery identity, idempotent processing | provider webhook tests |
| SSRF through provider or health URLs | provider base URL and health URL validation, no URL credentials, bounded HTTP clients; production egress policy | SSRF regression tests and edge review |
| Command injection on a VPS | structured arguments, strict name/path/image validation, connector-side allowlist, no generic shell operation | connector validator and command tests |
| Connector credential replay | one-time enrollment, mTLS client identity, certificate rotation grace, immediate revocation, command IDs and cached results | enrollment/rotation/replay tests |
| SSH machine-in-the-middle | per-server keys and trust-on-first-use host-key pinning | changed-host-key test and onboarding check |
| Secret disclosure in output | value masking, encrypted connector payloads, bounded redacted results, never return credentials from read APIs | masking tests and adversarial log cases |
| Registry blob corruption or unsafe upload | Distribution-compatible validation, supported Linux volumes, offline garbage collection | registry upload and restore tests |
| Destructive or stale rollback | immutable deployment inputs, exact target confirmation, protected-environment policy, fresh approval where required | rollback and superseded-target tests |
| Audit history alteration | append-only API model; application identities have no update/delete route | audit tests and database privilege review |
| Denial of service | request/body limits, build concurrency, step timeouts, resource limits, bounded queues/logs/SSE clients | load and disk-full tests |
Managed deployment assumptions
- Each customer receives an isolated hub, rootless BuildKit stack, volumes, network, encryption key, domain, quota, and backup set.
- Customer builds never run on Echo or another shared production edge.
- The managed router forwards only documented HTTP and connector endpoints.
- Connector TLS is passed through to the hub; a proxy must not impersonate connector client certificates.
- BYO compute is not trusted as part of the managed control plane. Results are attributed to the enrolled worker and must not grant billing or approval authority.
- Managed hosted-compute policy requires the dedicated
managed:writescope. The initial bootstrap principal may grant that scope during provisioning to the cloud control identity; ordinary admin scope does not imply it and public PAT creation rejects it. Existing cloud control identities receive the scope through a forward-only migration.
Residual risks and non-goals
Builds intentionally execute customer code. A compromised dependency can read secrets explicitly granted to that repository and can publish a malicious image. ReaperCI reduces blast radius and records the action; it cannot prove source-code intent. Direct SSH also gives the configured Unix account every permission that account already has. Operators must use dedicated least-privilege accounts.
Kubernetes, Windows production runners, arbitrary remote shell, repository issues, pull-request review, and multi-region high availability are outside the GA threat model.
Release security gate
Before beta or GA, record evidence for secret masking, authorization boundaries, provider signatures, connector enrollment/rotation/revocation, backup restore, upgrade rollback, malicious repository inputs, SSRF, command injection, CSRF, rate limits, build resource limits, and amd64/arm64 runtime smoke. A known critical or high issue blocks release. Security exceptions require an owner, expiry date, exploitability analysis, and compensating control.