{"schema":"immiscible.trust.v1","generatedAt":"2026-10-10T21:43:41.842Z","version":"2530cb491bcc","build":{"commit":"2530cb491bcc0a7e38e385b238e0cf6ba035510e","builtAt":"2026-10-10T10:51:58Z"},"deployment":{"mode":"cloud","production":true,"publicUrl":"https://immiscible.fly.dev","region":{"id":"eu","name":"EU","place":"Frankfurt, Germany"}},"regions":[{"id":"eu","label":"EU (Frankfurt, Germany)","url":"https://immiscible.fly.dev","here":true}],"controls":[{"id":"transport","title":"HTTPS with HSTS","enforced":true,"detail":"PUBLIC_URL must be https; every response carries Strict-Transport-Security for two years with includeSubDomains and preload."},{"id":"session_cookie","title":"Session cookie","enforced":true,"detail":"HttpOnly, SameSite=Lax, Secure, with the __Host- prefix; stored server-side only as a SHA-256 digest; rotated when a person's privileges change."},{"id":"session_limits","title":"Session lifetimes","enforced":true,"detail":"A session ends after 1440 minutes idle and 14 days after sign-in, whichever comes first. A workspace can set shorter limits for its members."},{"id":"csrf","title":"Cross-site request forgery","enforced":true,"detail":"State-changing console requests need a custom header and a matching Origin; the cookie is SameSite=Lax."},{"id":"content_security_policy","title":"Content Security Policy","enforced":true,"detail":"Pages are served with a strict CSP: no inline script, frame-ancestors 'none'."},{"id":"passwords","title":"Passwords","enforced":true,"detail":"scrypt with a per-password salt; at least 10 characters. Sign-in attempts are limited to 10 a minute per IP address, and counted per account whatever address they come from."},{"id":"two_factor","title":"Two-factor authentication","enforced":true,"detail":"Authenticator apps (TOTP, RFC 6238) with single-use recovery codes, and passkeys (WebAuthn, user verification required to sign in). A workspace can require two-factor for every member."},{"id":"step_up","title":"Step-up for consequential actions","enforced":true,"detail":"Approving a payment or other amount above the workspace’s line, releasing personal data, changing single sign-on, changing the security policy, changing retention, making someone an owner, admin or security admin, minting a provisioning or service token, exporting or deleting the workspace and removing a second factor each need a proof of who is behind the session from the last 5 minutes: a passkey or authenticator code when the person has one, otherwise their password or an emailed code."},{"id":"sso","title":"Single sign-on","enforced":true,"detail":"OpenID Connect (authorization code with PKCE) for Okta, Microsoft Entra, Google Workspace and any OIDC provider; email domains proven by DNS TXT record. A workspace can require it for its verified domains, with an owner break-glass (a passkey or authenticator code). SAML 2.0 is supported per workspace, SP-initiated, with signed assertions required: it checks the signature against the certificate the workspace pinned (SHA-256 or stronger), the audience, recipient and validity window with one minute of clock skew, binds each response to a stored single-use request and the browser that started it, and accepts each assertion ID once. Sign-in started at the identity provider is off unless an owner turns it on."},{"id":"sign_in_methods","title":"Allowed sign-in methods","enforced":true,"detail":"A workspace can limit which of these reach it: password, email, google, microsoft, okta, passkey, sso. Personal sign-in providers configured here: google, microsoft."},{"id":"scim","title":"SCIM 2.0 provisioning","enforced":true,"detail":"Users and groups at /scim/v2 with a bearer token per workspace; deactivating a person removes their access and revokes their keys within the request."},{"id":"ip_allowlists","title":"IP allowlists","enforced":true,"detail":"A workspace can limit console and API access (keys, agent keys, service tokens, OAuth tokens and the phone app) to IPv4 and IPv6 ranges. A list that would lock out the person saving it is refused."},{"id":"roles","title":"Role-based access","enforced":true,"detail":"Roles: owner, admin, analyst, auditor, member, approver, security admin (security). Every workspace route checks the caller's role before it reads or changes anything."},{"id":"audit_log","title":"Audit log","enforced":true,"detail":"Sign-ins, role changes, rules, approvals, stops, settings, keys and integrations, each with the person, address and browser; filterable and exportable as CSV or JSON. Entries are also chained into the evidence ledger."},{"id":"evidence","title":"Tamper-evident evidence","enforced":true,"detail":"A hash-chained ledger (SHA-256) written before each response returns, with Ed25519-signed receipts and checkpoints that can be verified offline. Signed evidence records are never purged by retention; export access windows depend on plan."},{"id":"encryption_at_rest","title":"Secrets sealed at rest","enforced":true,"detail":"Provider keys, single sign-on client secrets, connection tokens and vault fields are sealed with AES-256-GCM, bound to their workspace, under a deployment key. The database file itself is not encrypted by the application."},{"id":"key_management","title":"Key management","enforced":true,"detail":"One deployment master key (IMMISCIBLE_MASTER_KEY), held only in the runtime environment and never written to the database. Rotation: start with the new key and the old one as IMMISCIBLE_MASTER_KEY_PREVIOUS, run `immiscible-server rekey` to re-seal every stored secret, then remove the old key (docs/deploy.md). Receipts and checkpoints are signed with an Ed25519 key sealed under the master key; its public half is published at /.well-known/immiscible-keys.json. `immiscible-server rotate-signing-key` replaces it: the new key signs from then on, the retired key stays published so what it signed still verifies, and the rotation is recorded in every workspace's evidence ledger."},{"id":"backup","title":"Backup and restore","enforced":true,"detail":"Every hour the database is copied while the service keeps serving; the copy's integrity and every workspace's evidence chain are checked, then it is compressed, sealed with AES-256-GCM under a key derived from the master key, and uploaded to S3-compatible object storage off this machine with a manifest of its hashes. Recovery point: about an hour of writes. Copies are kept at least 35 days. The service never deletes a backup itself; old copies are removed only by the operator, separately. A restore checks the download's hash, the GCM tag and the decrypted file's hash, and recomputes every evidence chain against the manifest, before it touches the live database; that whole round trip runs in the automated tests on every build. Last good backup: 2026-10-10T20:52:29.707Z. No timed restore drill of this deployment is recorded yet."},{"id":"data_residency","title":"Data residency","enforced":true,"detail":"This deployment is the EU (Frankfurt, Germany) region. A workspace is created in the region its owner picks at sign-up and its records stay there: each region is a separate deployment with its own database, encrypted backups under its own storage prefix (a restore refuses a backup from another region), and its own signing key. Only public signing keys are shared, so a receipt from any region verifies against either region's published key set. Self-hosting keeps all data in the customer's own environment."},{"id":"incident_response","title":"Incident response and breach notice","enforced":true,"detail":"Personal data breaches are notified to the customer without undue delay and in any case within 48 hours (Data Processing Agreement, on request until it is published). Security reports go to https://immiscible.fly.dev/contact?topic=security, as /.well-known/security.txt says."},{"id":"data_retention","title":"Data retention","enforced":true,"detail":"A workspace can set how long call logs and prompt metadata are kept, within its plan; a daily job removes what is older and records each purge in the ledger. Signed evidence records are never purged by retention; export access windows depend on plan."},{"id":"email_verification","title":"Email verification","enforced":true,"detail":"An unconfirmed address cannot invite people or mint credentials."},{"id":"domain_capture","title":"Domain capture","enforced":true,"detail":"Sign-ups on a domain a workspace has verified ask to join that workspace; an owner approves."},{"id":"signups","title":"Open sign-up","enforced":true,"detail":"Anyone can create an account."},{"id":"dependencies","title":"Runtime dependencies","enforced":true,"detail":"None for the core beyond Node.js itself. SAML sign-in loads one optional library, @node-saml/node-saml with xml-crypto and @xmldom/xmldom, pinned to exact versions in package-lock.json, and only when a workspace uses SAML."},{"id":"deletion","title":"Workspace deletion and erasure","enforced":true,"detail":"Deleting a workspace revokes its keys and removes stored provider keys at once. 30 days later every record carrying the workspace's id is erased: members, agents, rules, approvals, vault fields, calls, the audit log and the evidence ledger with its checkpoints. Until then an owner can cancel. A workspace under a legal hold cannot be deleted. What is kept is a signed erasure statement holding counts and hashes (the ledger's final head hash, the last checkpoint) and no personal data; the owners are emailed a certificate of erasure, also downloadable. The erasure job runs hourly on this deployment."},{"id":"export","title":"Full workspace export","enforced":true,"detail":"An owner can download the whole workspace as one zip after a step-up: settings without secrets, members, agents, rules, approvals, spend, the audit log, and the evidence ledger with its signed checkpoints, the public keys and a stand-alone verifier. Each download is in the audit log and the evidence ledger."},{"id":"ai_content","title":"Prompt and answer content","enforced":true,"detail":"Recorded as SHA-256 digests with character counts by default; the text is kept only for task classes a workspace sets to retain. Requests go to the workspace's own model provider under its own key; nothing is used to train models."}],"backup":{"method":"scheduled","enforced":true,"intervalMinutes":60,"recoveryPointMinutes":60,"keepHourly":48,"keepDaily":35,"lastSuccessAt":"2026-10-10T20:52:29.707Z","lastRestoreDrill":null},"evidenceExportWindowDays":[{"plan":"sandbox","days":7},{"plan":"team","days":365},{"plan":"business","days":3650},{"plan":"scale","days":3650}],"notSupported":["Encrypted SAML assertions (assertions must be signed; transport is HTTPS).","Single logout (OIDC back-channel logout, SAML single logout).","Geolocation of sign-ins: sessions show the address, not a place."],"certifications":[],"documents":[{"title":"Security review pack","url":"/trust/pack.zip","format":"zip"},{"title":"Data Processing Agreement","url":"/legal/dpa"},{"title":"Sub-processors","url":"/legal/subprocessors"},{"title":"Security contact","url":"/.well-known/security.txt"}]}