Security
Envelope-encrypted secrets, SSRF egress control, log redaction, and multi-tenant isolation.
Siphon runs untrusted connector specs against a tenant's credentials, so security is structural, not bolted on.
Secrets: envelope encryption
Connection secrets are envelope-encrypted (AES-256-GCM). Each secret is
encrypted with a per-secret data key, which is itself wrapped by a key-encryption
key (KEK) supplied via SIPHON_KEK. The stored ciphertext records a keyVersion,
so the KEK can be rotated without re-encrypting existing data.
KEK must match across processes
The app, worker, and scheduler must share the same SIPHON_KEK — otherwise a
secret encrypted by one process can't be decrypted by another. Decryption of a
bring-your-own warehouse DSN happens in the worker handler body, never inside the
durable journal.
SSRF egress control
Every outbound request from the engine passes an egress guard before it's sent: the resolved address is classified and blocked if it targets a private, loopback, or link-local range. Redirects are re-validated (a public URL can't 302 into the metadata endpoint), and an egress block is never retried. This is the innermost layer of the HTTP client stack.
Log redaction
The call log the Run Inspector renders is redacted before it's persisted — auth headers, tokens, and secret-derived values are stripped. Because the auth token exchange flows through the same logging client, redaction covers login requests too.
Multi-tenant isolation
The tenancy model is organization → workspace → connection. Org isolation is enforced in the service layer — every run/quarantine/connection query is org-scoped, and an IDOR regression test proves cross-tenant access is denied.
Row-level security is the belt-and-suspenders layer beneath that. Policies
enforce isolation at the database when a request sets its org context (via the
withOrg hook, SET LOCAL app.current_org), and are permissive when unset so the
rollout is safe. The foundation is in place and proven at the DB layer (a
non-superuser role with org A's context can't read org B's rows, at direct, 1-hop,
and 2-hop table depths); full enforcement activates when the app connects as a
dedicated non-superuser role — a superuser bypasses RLS. See ADR 0013.
Workspace access control
Within an org, access is scoped per workspace (ADR 0016). Org owners and admins implicitly manage every workspace. A plain member only reaches the workspaces they've been granted, at one of two roles:
- Admin — can create and manage connections in that workspace.
- Viewer — read-only.
Grants live in workspace_members and are managed by an org admin in
Settings → Workspace access. Enforcement is server-side: the workspace
switcher and the connections list only surface workspaces a user can access, and
creating a connection requires an admin grant on the target workspace. Org-level
actions (creating or renaming a workspace, granting access) are restricted to org
admins.
Tokens & API keys
- API keys authenticate the
/api/v1REST surface; they're stored hashed (SHA-256), scoped, and revocable. - Embed tokens are short-lived and connection-scoped — safe to hand to a browser (see Embed).
- Admin UI access is magic-link login with org switching.
Audit log
Sensitive actions append to an immutable audit log (actor, action, target, metadata) for after-the-fact review.