Security & trust

Security model

Least-privilege and read-only by design, first-party identity with mandatory MFA, hard per-tenant isolation, and a cryptographic audit spine you can verify yourself.

TrustFix is built so a security engineer can independently verify our claims rather than take them on faith. The model rests on least-privilege read-only access, first-party identity with mandatory MFA, hard per-tenant isolation, and a cryptographic audit spine.

Read-only, least-privilege access

TrustFix reads your estate through least-privilege, read-only connectors and never writes to your infrastructure during connection or scanning. Cloud connections favor short-lived federation over stored secrets:

  • AWS — cross-account sts:AssumeRole with a server-derived External ID, which prevents confused-deputy attacks: only TrustFix, from its specific principal, can assume your role even if an attacker knows the ARN. The recommended template grants only the specific read actions needed and never reads secret, parameter, or object values.
  • GCP and AzureWorkload Identity Federation, so no long-lived service-account keys or client secrets are stored on either side.

Every scan uses fresh temporary credentials that expire automatically and are never written to disk or logged. TrustFix never stores cloud access keys or secret keys, and all fix recommendations are delivered as pull requests that require human review — there is no automated remediation that touches your infrastructure directly.

First-party identity with mandatory MFA

Authentication is first-party (TFID); the prior third-party IdP dependency has been removed. The principal is resolved from an opaque, database-validated session cookie at a single server chokepoint that fails closed — edge middleware only does a cheap cookie-presence and CSRF pre-check, never the authoritative decision.

  • MFA is mandatory. A session that hasn't satisfied MFA is not a usable principal. TOTP and WebAuthn passkeys are supported; TOTP secrets are sealed at rest (AES-256-GCM), step-replay is rejected, recovery codes are single-use, and a passkey signature-counter regression (cloned-authenticator detection) is rejected. You cannot remove your last factor.
  • SSO — per-tenant SAML 2.0 / OIDC with group-claim → role mapping and optional SSO-only enforcement, gated on the tenant's entitlement.
  • Auth events are recorded durably, and identity-lifecycle and privilege events (access provisioned, role changed, account suspended) are additionally anchored in the Trust Ledger — hash-only, so no emails, roles, or secrets enter the ledger.

Role-based access control

Org membership uses four roles in a strict hierarchy — VIEWER < MEMBER < ADMIN < OWNER — and every check resolves the role from the database, never from a session claim:

CapabilityOWNERADMINMEMBERVIEWER
View findings, view team
Generate fix, create PR, run scan
Connect AWS, install GitHub, invite members, manage roles, view audit log
Manage billing

The most sensitive actions are OWNER-only — member role changes (confirm-stepped and last-OWNER-protected) and SSO editing/enforcement. SSO and SOC 2 evidence export resolve per-tenant entitlements, and entitlements are strictly tenant-scoped — one tenant's never affects another's. Teams can scope a member to specific AWS accounts and repos; a member in no team sees nothing, and a team with no scopes acts as an all-access team.

Operator support uses a separate, time-boxed, read-only "View-As" path, available only to super-admins defined by an environment allowlist (no database flag, by design). The override is HMAC-signed, honored only on safe HTTP methods, entirely disabled when its signing secret is unset, and every entry and exit is audited and surfaced to the customer.

Per-tenant isolation by construction

Isolation is defense in depth across two independent layers:

  1. Manual org-scoping via an orgScope() primitive used across the read paths.
  2. A structural Prisma backstop: requests run inside a request-scoped tenant context, and a query hook for tenant-resource models injects organizationId when omitted and rejects any query targeting a different org with a fail-closed CrossTenantQueryError.

The read org resolver (which honors read-only View-As) is separated from a write-safe resolver that never honors View-As, so a write on a GET transport (an OAuth callback, an export download) can never land in a View-As target tenant.

The cryptographic audit spine

Every consequential action is recorded in the per-tenant Trust Ledger — append-only, hash-chained, Ed25519-signed, with Merkle inclusion proofs. verifyChain recomputes every hash, link, and signature, so any mutated, reordered, or forged row breaks it; an inclusion proof lets an auditor re-verify a single action offline. Agent-passport revocation is published as a signed Token Status List plus an agent CRL for O(1), herd-private, offline revocation checks.

Credential handling and data lifecycle

Any long-lived secret that must be held (OAuth tokens, PATs) is sealed with KMS envelope encryption (AES-256-GCM) and bound to the organizationId as encryption-context AAD, so a decrypt attempt against a different org fails at the KMS layer. API keys store only a SHA-256 hash — the plaintext token is shown exactly once. OAuth flows use PKCE. On offboarding or a right-to-be-forgotten request, PII payloads are tombstoned while the signed ledger entries are preserved and still chain-verify — proving a record existed without retaining the personal data.