Security model

Confirm sits between your agents and their most dangerous actions, so its own security model has to be legible. This page is the honest version — what we store, what we sign, and what the trust boundaries are.

Credentials at rest

  • API keys (cfm_live_…) are stored as SHA-256 hashes. The plaintext exists only in the moment of creation, on your screen. A key prefix is kept for dashboard display; revocation is immediate.
  • Magic-link tokens are 256 bits from a CSPRNG, also stored only as hashes. The plaintext lives solely in the email link. A database leak therefore exposes neither the ability to create requests nor the ability to approve them.
  • Webhook secrets (whsec_…) are per-endpoint and shown once.

Approval authentication

Approvers authenticate by possession: the unguessable token in the magic link. Each token is bound to exactly one request, is single-use in effect (terminal states can't be re-resolved), and dies at the request's TTL. Every resolution additionally records the approver's email identity, IP address, and user agent — so possession is accountable, not anonymous.

A forwarded approval email means a forwarded capability — the same trust model as a DocuSign or password-reset link. Send approvals to individuals or tightly-scoped aliases, not broad distribution lists. Slack-based approvals with workspace identity are on the Enterprise roadmap.

Single-resolution guarantee

Approve/reject transitions are guarded compare-and-set updates: they succeed only from PENDING. Two people clicking simultaneously, a double-submit, or a decision racing the expiry sweep produce exactly one verdict; all later attempts receive an "already resolved" error. There is no code path that flips a terminal state.

Webhook integrity

Every delivery is signed with HMAC-SHA256 over a timestamped payload using your endpoint's secret, sent as X-Confirm-Signature: t=<ts>,v1=<hex>. Verifying the signature proves origin and integrity; enforcing a timestamp tolerance blocks replays. Endpoints must be HTTPS in production.

Audit trail

The audit trail is structural, not a feature flag: requests, resolutions, and webhook delivery attempts are written as append-only rows. What the agent proposed, what the human changed it to, who decided, when, from where, and what your systems were told — each is a separate immutable record. Nothing in the product mutates history.

Tenancy & transport

  • Every resource is scoped to a workspace; API keys can only read and create within their own. Cross-tenant reads return 404, not 403 — existence is not leaked.
  • All traffic is TLS. Data is encrypted at rest by the underlying Postgres provider.
  • Approval emails contain the summary you provide and the link — put secrets in payload (shown only on the review page), not in summary.

Reporting

Found something? Email security@confirm.dev. We commit to acknowledging reports within one business day.