Security boundary
Identity and authorization (0.4.0)
Four principal classes — human, automation, application, runner — with a capability catalogue that bounds what each class can ever hold (Authorization model). Application credentials resolve and report; they cannot register, promote, deploy, roll back, approve, manage access, read traces or bindings. Every Registry route declares its capability; the router enforces it before handler work, then Project and environment scope; authorization precedes routing. Service credentials are issued by the Registry, shown once, stored as SHA-256 digests with a 4-character hint, rotatable, revocable and disable-able with immediate effect; machine-credential denials of mutating routes are audited. Approval and break-glass are human-only; separation of duties is available per environment.
Registry member credentials have at least 24 characters, come from env:/keychain: references and persist as digests in a credentials table. Child-runtime tokens live only in process memory. Credentials carry prefixes (scw_app_, scw_ci_) that Build, trace, provider and delivery scanners refuse.
Secrets for live providers
Bindings contain secret references only, restricted to the Registry's allowlist (providerSecretRefs, default env:CONTEXT_PROVIDER_* and keychain:context-provider-*) and never the references used by Registry members — otherwise a binding could send the Registry's own credential to an attacker-chosen endpoint. The deployment runner resolves exactly the references the binding names and passes them to the runtime as CONTEXT_PROVIDER_SECRET_<n>; the runtime's environment contains nothing else from the Registry (verified on Linux via /proc/<pid>/environ). Values never enter Projects, Builds, bindings, deployment records, health responses, traces or logs.
Live providers and SSRF
The destination of a provider call comes only from the Admin-managed binding: absolute HTTPS (HTTP only on loopback), no userinfo, query or fragment, redirects refused. Request input can only become the lookup value, sent in a JSON body after validation against a strict character set and the Project's pattern; it cannot change host, path or query. Internal-network endpoints are legitimate for internal APIs and are therefore an operator decision recorded in an audited binding revision, not something request data can reach. Responses are bounded (time, bytes, items, item size), scanned for secret patterns and reflected credentials, and rendered as reference data under the data notice; they are never executed and grant no authority. Literal link-local addresses and cloud metadata hostnames (169.254.0.0/16, fe80::/10, fd00:ec2::254, metadata, metadata.google.internal, metadata.azure.com) are refused as provider endpoints; DNS-level egress control remains the operator's network policy. SQLite providers open their database read-only with query_only and plain-identifier SQL, and the database path (symlinks resolved, at binding save and again at deploy) may never lie inside the Registry's data directory — which holds every organization's records — and must lie inside providerDatabaseRoots when the operator configures them (recommended for multi-tenant Registries, together with OS file permissions).
Builds, signatures and supply chain
Signatures bind Build identity/digest, complete immutable artifact digest, runtime contract and provenance digest (UNSIGNED, SIGNED_VALID, SIGNED_INVALID, SIGNER_UNKNOWN). Signature policy is never bypassed, including by break-glass. Artifact objects are content-addressed and re-verified on every read; tampered or missing objects are refused. Releases carry a signed attestation binding source commit, artifact and proof digests (Release attestation).
Bounds and transport
Loopback default; authenticated non-loopback runtimes; no browser-origin requests; loopback Host validation. Registry bodies ≤ 64 MiB, artifacts ≤ 48 MiB, traces ≤ 2 MiB/100 records, 16 concurrent requests, 3000/minute per principal, 24 deployments per runner. Remote access needs an operator TLS boundary. Filesystem owners can read or change local data; cryptographic verification detects alteration but local-personal mode does not defend against the OS account owner.
Tested
Least privilege per class (allowed and denied operations), class bounds on grants, revocation/rotation/disable, cross-Project, cross-environment and cross-organization denial, plaintext absence at rest, route-table invariants, separation of duties, break-glass rules, binding validation (missing, incompatible, unresolvable, non-allowlisted, reserved, plaintext), provider bounds (timeout, size, reflection, secret patterns, unsafe input), secret isolation of runtime processes, trace correlation and history conflicts, tampered CAS objects, attestation tampering. FUTURE: SSO, HSM-held keys, vault providers, untrusted-connector sandboxing, multi-host hardening.
Historical investigation and decision-provider audit (0.6.0)
Historical operations enforce current organization/project scope, separate trace metadata/content capabilities, Build access and explicit reproduction permission. An empty reproduction body is mandatory; retained fixtures and embedded artifacts are the only replay dependencies. Cross-project references and malformed/ambiguous observation envelopes fail closed. Candidate evaluation never contacts live sources. Response material preview is bounded; request redaction and expiration can only reduce reproduction confidence. Application consumption reports remain unverified producer observations.
The external TypeSafe/Jev decision adapter requires HTTPS except explicit loopback HTTP for testing. URLs with userinfo, query or fragment are rejected; redirects are disabled, preventing Bearer forwarding. Replies are streamed with a 64 KiB bound and bounded JSON depth. Probability labels, finite [0,1] values, sum, maximal choice and confidence consistency are checked before use. Malformed replies preserve explicit deterministic fallback. No additional provider is introduced.
Tool execution boundary
Tool schemas and profile disclosure travel with the immutable v2 Build. The gateway validates exact context, arguments, executor contract and call limit before dispatching to a fixed binding endpoint. Writes require an expiring exact-call approval through a human-only Registry capability and a separate runner credential; applications and automation cannot grant themselves approval. The backend still enforces domain/tenant authorization. Dispatch intent persists before I/O; UNKNOWN and duplicate receipts never cause an automatic second dispatch. Raw arguments/results/reasons are not retained; fingerprints are keyed. A tool Runtime owns its data directory before any retention work; competing live/foreign-host owners are refused. Full contract.
The shared web host
On app.seifprotocol.com every engine operation that can read sources, hold credentials or reach the network runs in a child process of its project, with a minimal environment, the project's own vault key (derived, never written to disk) and a memory limit. runtime/engine/egress-guard.mjs refuses private, loopback, link-local and cloud-metadata addresses on the address actually dialled (DNS rebinding included), and runtime/engine/confine.mjs keeps file, Git and database sources inside the project folder. The hosted MCP endpoint answers as one bound profile and never names material that profile may not receive. Details: web/README.md.