Security threat model
This model applies to the supported self-hosted Compose topology in the documentation revision where it appears. It covers the four application trust boundaries below. Browser and identity-provider internals, host and database administration, backup custody, the CI/release supply chain, and edge DDoS protection are separate control planes owned by the Security Policy, Production Setup, Backup & Restore, and Release Image Lock.
Security objectives and protected assets
Hephaestus must:
- prevent one workspace from reading or changing another workspace's data;
- keep reusable integration, session, encryption, and model-provider credentials out of untrusted content and sandbox environments;
- contain repository- and model-influenced execution without trusting its instructions or output; and
- authenticate and bound public ingress and restrict outbound destinations and side effects.
| Asset | Examples |
|---|---|
| Reusable credentials | Provider keys, OAuth secrets, integration tokens, webhook secrets, encryption keys |
| Workspace-confidential data | Repository content, issues, messages, documents, feedback, membership |
| Untrusted content | Webhook bodies, diffs, files, comments, chat, documents, model output |
| Operational data | Job and delivery identifiers, metrics, sanitized error categories |
System and data flow
Arrows show permitted logical flows, not network-level reachability. In particular, the application-server container joins each internal sandbox network; application route security remains part of that boundary. Runtime-role separation reduces reachable surface but is not authorization; see Runtime Roles.
Attacker assumptions
Assume an attacker can be:
- an unauthenticated internet client calling every route exposed by the reverse proxy;
- a legitimate member attempting horizontal or vertical privilege escalation;
- a compromised integration account sending correctly signed malicious content;
- a repository contributor placing prompt injection, malicious source, symlinks, or resource-exhaustion inputs in synchronized artifacts;
- a malicious or compromised model endpoint returning crafted output; or
- code executing inside a sandbox with full knowledge of the image and application design.
The Docker daemon, host root, running application processes, PostgreSQL administrator, instance encryption key, and configured instance administrators are trusted. Compromise of those principals is outside the isolation guarantees described here.
Mitigations index
Each table links threats to enforcement, verification, and residual risk.
Boundary 1: public webhook ingress
| ID and threat | Enforced control | Enforcement | Verification | Residual risk |
|---|---|---|---|---|
| WH-1 — forged or unsupported provider event | Resolve a known integration kind and verify the provider-signed raw bytes before parsing. Missing routing, verifier, or subject derivation fails closed. | IntegrationKindRouting, WebhookIngestPipeline | IntegrationKindRoutingTest, WebhookIngestPipelineTest, provider signature-verifier tests for GitHub, GitLab, Slack, and Outline | A valid signature does not make content safe and cannot detect a compromised provider account. Replay resistance differs by provider; GitHub and GitLab rely on bounded deduplication, after which consumers can receive a replay again. |
| WH-2 — oversized input or queue overload | Require a declared request size within the configured limit and fail startup when the broker cannot accept that size. | WebhookPayloadSizeFilter, WebhookPayloadCapacityCheck | WebhookPayloadSizeFilterTest, WebhookPayloadCapacityCheckTest | Volumetric filtering and rate limiting remain edge responsibilities. |
| WH-3 — acknowledged loss or duplicate processing | Events selected for durable processing return success only after JetStream accepts them. Per-kind stable keys use provider delivery identifiers where available. | WebhookIngestPipeline | WebhookIngestPipelineTest, WebhookIngestionCannotFailSilentlyTest | Protocol challenges and deliberately filtered events respond without publishing. Deduplication expires with broker retention, so consumers must tolerate redelivery. |
Route only /webhooks/** to a separately exposed webhook role and operate its capacity and retry signals as described in Webhook Ingestion Operations.
Boundary 2: LLM agent sandbox
Repository, chat, and model content is untrusted and can influence tool use. Model output remains untrusted; any path that persists it or creates an external write must apply that operation's validation and authorization.
| ID and threat | Enforced control | Enforcement | Verification | Residual risk |
|---|---|---|---|---|
| SB-1 — privilege escalation, host escape, or resource exhaustion | Apply non-privileged execution, dropped capabilities, no-new-privileges, private cgroup/IPC namespaces, seccomp, CPU/memory/PID/file limits, disabled core dumps, and bounded nosuid,nodev tmpfs mounts with noexec where compatible. | ContainerSecurityPolicy | SandboxArchitectureTest, DockerSandboxAdapterTest, DockerSandboxLiveTest | The root filesystem is writable and standard Docker shares the host kernel and daemon. Use gVisor and dedicated, patched worker hosts for hostile multi-tenant workloads. Never mount the Docker socket or secret-bearing host paths into a sandbox. |
| SB-2 — provider-secret theft or proxy abuse | Keep the provider key in the application catalog. Job credentials are accepted only while the job is running; mentor credentials follow the live session lifecycle. The proxy binds requests to the admitted connection, model, API, and path. | ADR 0006, JobTokenAuthenticationFilter, LlmProxyController | JobTokenAuthenticationFilterTest, LlmProxyControllerTest, SandboxEnvBlocklistTest | The worker-side application process holds catalog credentials. A third-party worker is not trusted under this topology; #1166 owns that design gap. |
| SB-3 — network exfiltration or cross-execution access | Create per-execution Docker resources. With internet access disabled, use an internal network with no external route and configure an unusable DNS resolver. | SandboxNetworkManager, ContainerSecurityPolicy | SandboxNetworkManagerTest, DockerSandboxLiveTest | The job network can reach other application-server routes; those routes must independently authenticate and authorize sandbox-originated requests. internetAccess=true creates a normal bridge, not a hostname allow-list. |
| SB-4 — persistence after execution | Reconcile managed containers and networks against durable job state. | SandboxReconciler | SandboxReconcilerTest | Host or daemon compromise is outside this control. |
Boundary 3: outbound egress
Destination policy and delivery policy are distinct: one limits where a client may connect; the other limits whether Hephaestus may create an external side effect.
| ID and threat | Enforced control | Enforcement | Verification | Residual risk |
|---|---|---|---|---|
| EG-1 — LLM-provider SSRF or DNS rebinding | Require a public HTTPS provider URL without userinfo, query, or fragment; apply the optional hostname allow-list; repeat the private-address check on the DNS result used to connect. | EgressPolicy, LlmProxyWebClientConfig | EgressPolicyTest, LlmProxyWebClientConfigTest | An allowed public service may itself proxy arbitrary destinations or become compromised. Keep the allow-list narrow. |
| EG-2 — unsafe integration origin | Reject non-HTTPS origins, embedded credentials, paths, queries, fragments, and literal non-public addresses for user-configured SCM, login-provider, and Outline origins. | ServerUrlValidator | ServerUrlValidatorTest | This validator performs no DNS lookup. GitLab preflight, Outline API, and Outline identity calls use guarded connect-time resolution; this is not a uniform guarantee for every configurable login-provider client. |
| EG-3 — unapproved external write | Route supported delivery adapters through the instance silent-mode guard and reject unregistered adapter shapes in architecture tests. | OutboundEgressGuard, @OutboundEgressGateway | OutboundEgressGuardTest, OutboundEgressArchitectureTest | Silent mode governs supported writes; it is not a network kill switch and does not suppress reads or authentication traffic. |
| EG-4 — disclosure of stored integration credentials | Encrypt credential fields mapped through the converter with AES-GCM and bind their ciphertext to the owning row and purpose. | ADR 0014, EncryptedStringConverter | EncryptedStringConverterTest, EncryptionContextTest | Application or encryption-key compromise exposes decryptable values. Rotate credentials upstream after exposure; #543 tracks encryption-key versioning and rotation. |
Application destination controls do not constrain a sandbox granted broad internet access. Enforce any such exception through an independent network egress policy.
Boundary 4: SQL-layer workspace tenancy
Workspace authorization is the primary boundary. SQL inspection is a defect detector for recognized query shapes, not row-level authorization.
| ID and threat | Enforced control | Enforcement | Verification | Residual risk |
|---|---|---|---|---|
| TN-1 — object-ID substitution or role escalation | Resolve the authenticated account's workspace membership and role before protected workspace operations. | WorkspaceSecurityExpressions | WorkspaceAccessServiceTest, CrossTenantIsolationIntegrationTest | This control applies only where membership is checked; a user-supplied identifier is not proof of ownership. |
| TN-2 — query accidentally omits tenant scope | With enforcement set to throw, reject recognized SQL shapes that reference dynamically inventoried workspace-scoped tables without a recognized tenancy shape. | ADR 0004, TenancyConfiguration, WorkspaceStatementInspector | WorkspaceStatementInspectorTest, WorkspaceScopedTablesTest | Inserts, accepted primary-key shapes, explicit bypasses, and analysis failures are not rejected. Any SQL containing the word workspace_id is accepted without proving predicate binding. Object authorization and tenant-bound repository methods remain required. |
| TN-3 — unnecessary cross-workspace bypass | Require an explicit @WorkspaceAgnostic scope for reviewed instance-wide work. | @WorkspaceAgnostic, WorkspaceAgnosticAspect | TenancyBypassTest, MultiTenancyArchitectureTest | The annotation grants a deliberate bypass; review its call path and query whenever it is added or changed. |
log allows a detected violation to execute and off disables inspection. Neither is a production setting. Database backups and direct SQL access bypass application authorization and need separate access control and encryption.
References and maintenance
- Threat modeling: OWASP and NIST SP 800-154
- AI systems: NIST AI Risk Management Framework and OWASP Top 10 for LLM Applications
- Webhooks: GitHub and Slack
- Network boundaries: OWASP SSRF Prevention Cheat Sheet and Docker security guidance
Update this page whenever a depicted flow, attacker assumption, boundary control, enforcement setting, or residual risk changes.