Skip to content
RateStack
Capability · Security

Security baked into the platform, not bolted on.

AES-256-GCM master-key encryption with online rotation. Append-only audit log with SHA-256 hash chain and actingAsOrgId for delegation. Published capability catalog (12 operational + 7 provider) at /v1/capabilities. Email/password plus Google, Microsoft, and Apple Sign-In. PII redaction on every log path.

Overview

What it is, in one paragraph

Persisted secrets — IMAP credentials, webhook signing secrets, app-level configuration — are encrypted with AES-256-GCM under a master key supplied via env. Rotation is online with both old + new keys present during migration. Identity is via email/password (bcrypt with reuse-window) plus Google, Microsoft, and Apple Sign-In. Sessions are opaque, server-side, with idle and absolute TTLs. Access control runs against a published capability catalog of 12 operational + 7 provider capabilities, exposed at /v1/capabilities; the JWT carries an org_roles claim and audit rows carry actingAsOrgId so cross-tenant delegation is unambiguous in evidence packets.

  • Encryption at rest

    AES-256-GCM via SecretEncryptor. Master key supplied via env; rotation supported online with the previous key still readable during migration.

  • Capability catalog

    12 operational capabilities (loan.read, loan.write, loan.share, loan.price, ratesheet.activate, lock.commit, etc.) + 7 provider capabilities. Published at /v1/capabilities for client integrations.

  • Org-delegation auditing

    Every cross-tenant action writes actingAsOrgId into common_audit_log. Wholesale lenders can prove which originator instigated each request.

  • SSO via OAuth

    Google, Microsoft, and Apple Sign-In. Apple's client_secret JWT is signed at runtime from an operator-supplied P-256 key, never persisted.

  • Account approval workflow

    New sign-ups land in PENDING. An admin approves or rejects; both paths trigger branded transactional emails. No automatic admin escalation.

  • Brute-force lockout

    Repeated failed logins lock the account on a sliding window. The lockout decision is rate-limited via bucket4j on Redis to prevent enumeration.

  • PII redaction

    PiiRedactor scrubs emails, phones, SSN-shaped numbers, and PANs from every outbound log and audit payload before persistence — including OTLP spans.

  • SSRF defense

    SafeUrlValidator blocks loopback, private, link-local, and cloud-metadata IPs. Per-service host allowlists for outbound integrations (scrape, webhook target, IMAP).

  • Audit hash chain

    common_audit_log linked by SHA-256(prevHash || canonical(row)). Mutating a row is detectable on the verify endpoint.

  • Mail stack security

    Postfix/Dovecot/Rspamd mail stack with DKIM/SPF/DMARC, TLS, and SAFE-DEFAULT relay. Certs migrated to Let's Encrypt HTTP-01 in 2026-05.

How it works

The pipeline, end to end.

Numbered steps from input to output. Each step maps to a specific subsystem you can inspect via OpenTelemetry.

  1. 1

    Persisted secrets are ciphertext

    Anything sensitive (IMAP password, webhook secret, app setting) goes through SecretEncryptor before insert. The DB only sees AES-256-GCM ciphertext + a per-row IV.

  2. 2

    Identity comes from one of four paths

    Email/password (bcrypt with reuse-window check), Google OIDC, Microsoft OIDC, Apple Sign-In. All four converge on the same opaque session ID.

  3. 3

    Sessions are opaque

    The browser holds an HttpOnly cookie containing an opaque session ID; the server-side store maps it to user identity, capabilities, and the upstream auth token. Never a JWT.

  4. 4

    Capability check on every authenticated call

    Capability checks run at the api-service layer before the call hits the rule engine or persistence. Denials return RFC 7807 with a stable correlationId.

  5. 5

    Rotation is online

    Set PRICING_MASTER_KEY_PREVIOUS to the old key and PRICING_MASTER_KEY to the new one; SecretEncryptor decrypts with previous, encrypts with current. Re-encrypt rows via the rekey endpoint, then drop the previous.

  6. 6

    Verify the audit chain

    GET /v1/admin/audit/verify recomputes the hash chain (including actingAsOrgId) and reports the first break, if any. Run it on a schedule from your monitoring stack.

Hands on

Read the published capability catalog

Live cURL sample — copy, paste, ship.

# Read the published capability catalog
curl https://api.ratestack.com/v1/capabilities \
  -H "X-API-Key: $RATESTACK_KEY"

# {
#   "operational": [
#     { "key":"loan.read",   "description":"Read loans within scope" },
#     { "key":"loan.write",  "description":"Create or update loans" },
#     { "key":"loan.share",  "description":"Grant TTL visibility to another org" },
#     { "key":"loan.price",  "description":"Run pricing on a loan" },
#     ...
#   ],
#   "provider": [
#     { "key":"provider.ratesheet.publish", ... },
#     { "key":"provider.lock.commit",       ... },
#     ...
#   ]
# }

Why this matters

The pain it removes.

Compliance answers in minutes

Encryption, capability catalog, SSO, hash chain, redaction — every claim maps to a subsystem. We can produce a one-pager from the platform itself.

Delegation is auditable

actingAsOrgId makes wholesale and TPO audits trivial. Every cross-tenant action carries the grantor org id in its audit row.

Operators sleep through key rotation

Online rotation means no maintenance window. Roll services with both keys, re-encrypt, drop the old. Done.

Frequently asked

Direct answers, no marketing spin.

Do you support SSO with a custom OIDC provider?

Today we ship Google, Microsoft, and Apple. SAML and arbitrary OIDC are available on Enterprise; talk to sales for activation.

What's your password policy?

12-character minimum, no common-password matches, no repeats from the last N passwords (configurable, default 5), bcrypt at cost 12. Account lockout after sustained failures.

How do you handle session revocation?

Sessions are server-side — revocation is a row delete; effective on the next request. We revoke on password change, role change, and explicit admin action.

Can I require SSO and disable password login?

On Business and Enterprise tiers, yes. The setting is per-organization and gates the UI in addition to the API.

How do you handle the secret encryption key?

It is supplied via env (PRICING_MASTER_KEY). We do not persist it. Rotation requires both keys present during the overlap window. KMS integrations are available on Enterprise.

What is actingAsOrgId for?

When org A holds a delegation grant from org B and uses it to operate on a loan, the audit row records actingAsOrgId=B and actor.orgId=A. Wholesale and TPO audits get unambiguous evidence of who initiated each action under whose delegation.

How we compare

Security baked into the platform, not bolted on. — vs the alternatives.

Specific angles, not generic feature checklists. Each row links to a longer side-by-side; we're transparent about where competitors are the better choice.

Comparisons reflect each vendor's public positioning. Where a fact is unverifiable, we mark it "Depends" or "Unknown" instead of guessing.

Ready to see it on your data?

Wire security baked into the platform, not bolted on. up to your real workflow.

We'll spin you a sandbox, load your actual ratesheets, and walk you through this capability against your top scenarios.

Security — encryption, capability catalog, SSO, audit chain | RateStack