SF Tether was built from first principles around a single constraint: agent credentials must never touch plaintext storage. Every control below is implemented, not aspirational.
[ VAULT LAYER ]
Every access token and refresh token is encrypted at the Drizzle column layer using AES-256-GCM before it reaches Postgres. A raw SELECT in psql returns ciphertext. No application code path can accidentally store plaintext — the encryption is wired into the schema type itself.
AES-256-GCM encryption with per-row IV, context-bound to the row's primary key so ciphertext from one row cannot be replayed against another
Credential rotation helper re-encrypts every vault credential under a fresh context without reading tokens into application memory
Drizzle auto-decrypts on SELECT — the decrypt path is the only path, with no raw-string escape hatch

[ ACCESS CONTROLS ]
The broker endpoint issues single-use, short-TTL tokens bound to the calling agent session. Provider credentials are never handed to agents directly.
Every key carries a scope: tether:broker, tether:read-connections, or tether:admin. Keys can be capped per-provider and per-day issuance limit.
Scope policy is checked both at connection creation and at every token issuance — tightening a policy takes effect immediately, not on the next re-auth.
The agent calls POST /api/broker/token with its SDK key, the end-user reference, and the scopes it needs. Nothing else.
Requested scopes are validated against the org's policy and the connection's granted scopes. Excess scopes return 400 with the specific missing set — no silent downgrade.
A provider access token is returned directly — Tether never mints its own opaque token. The issuance is written to the append-only audit log before the response returns.
[ AUDIT TRAIL ]
Two append-only tables — tether_connection_events and tether_broker_issuance_log — record every action with actor, IP hash, user-agent, scopes requested vs issued, and latency. UPDATE and DELETE are revoked at the database role level. Auditors get a unified, filterable log explorer with CSV and JSON export.
Connection events retained at compliance timescales; issuance log retained for 90 days hot with automatic partition archiving
IP addresses stored as SHA-256 hashes — raw IPs never persist (GDPR-aligned)
Each token reveal by an admin is logged as an admin.credential_revealed event — no silent inspection
Org-level data export for SOC 2 audits and GDPR data-portability requests, with a signed manifest

[ TENANT ISOLATION ]
Every tether_* table has RLS enabled with FORCE ROW LEVEL SECURITY — which means policies apply even when the database owner role executes a query. A request-path query without a valid tenant context returns zero rows, not a permission error — fail-closed by design.
Request handlers connect as tether_app (NOBYPASSRLS). Migrations and background workers connect as the owner role only when cross-tenant access is explicit. The two clients are never interchangeable.
The tenant context (app.tenant_id) is set in the same neon-http transaction batch as the query — the binding cannot outlive the transaction or leak to a reused connection.
A regression test seeds two tenants, queries as each, and asserts zero cross-tenant row visibility. This test runs in CI against a real Postgres instance — no mocked database.
One Tether account hosts many tenants. Every policy, allowlist, rate limit, connection, and credential is scoped to a tenant — accounts never see sibling tenants' data.

[ REVOCATION & CONSENT ]
Per-connection revocation calls the provider's revoke endpoint, zeroes the encrypted credential row, invalidates cached broker tokens, and emits a connection.revoked webhook — all idempotently. A break-glass Revoke ALL control covers the 'compromised admin laptop' scenario, requiring the org slug typed to confirm.
Before any OAuth redirect, end-users see a consent screen showing the embedding app's brand, the provider's logo, and each requested scope with a plain-English risk label. Consent shown, accepted, and declined events are logged. GDPR-aligned informed consent is not a checkbox — it is the redirect flow.
[ OAUTH SECURITY ]
The PKCE code_verifier is stored in a server-side pending-state table keyed by a signed JWT jti — it never appears in the redirect URL, browser history, or access logs.
Each OAuth state JWT contains a per-request nonce tracked in tether_oauth_state_log. A replayed state JWT returns 401 and logs a connection.error with subtype state_replay.
The returnUrl after OAuth must match the tenant's registered redirect-domain allowlist before the flow starts. Arbitrary redirect targets are rejected — no open-redirect surface.
[ RATE LIMITING & SSRF ]
Fail-closed rate limiter
If the KV store backing rate limits is unreachable, the limiter returns 503 with a Retry-After header — it never silently disables itself. A per-container in-memory fallback engages during sustained KV outage so a single container cannot be weaponised even when the distributed layer is down.
SSRF guard on webhook delivery
Every customer webhook endpoint URL is DNS-resolved on each dispatch. If any resolved address falls in RFC1918, link-local, loopback, or multicast ranges the delivery is refused before the request leaves the platform — protecting Tether's internal network from SSRF through customer-supplied URLs.
Token-leak redaction
Every error path that touches provider responses runs through a redact helper that removes access_token, refresh_token, Bearer, and Authorization values before they reach error monitoring. Provider error bodies are never echoed to API callers in raw form.
Concurrent refresh single-flight
Concurrent broker calls for the same connection serialize through a Postgres advisory lock — exactly one provider refresh HTTP call fires regardless of concurrency. A crashed process cannot strand the lock because pg_advisory_xact_lock releases on transaction end automatically.
[ HEALTH & OBSERVABILITY ]
The /api/health endpoint verifies encryption round-trip (encrypt a sentinel, decrypt it, compare), KV reachability, database connectivity, and that the request-path role is correctly bound — not just that the environment variables are set. 503 means something is genuinely wrong.
[ COMMON QUESTIONS ]
Every control described on this page is implemented and running. If you have specific security questions, email us directly at sf-core-org-support-sf-tether@saas-factory.ai — no form, no ticket queue.
Email our security team