Security
Built to hold customer books.
CubeLedger will hold bank tokens and wallet addresses. The v1 controls below are in the product. A SOC 2 audit is not. The readiness path is in docs/soc2-readiness.md in the repository.
Tenant isolation
Financial tables use Postgres row-level security. The web app connects as a role that does not own the tables and does not bypass RLS. A test signs in as that role and proves one tenant cannot read another.
Authentication
Email and password, TOTP authenticator codes, and passkeys. Session cookies are httpOnly. Login attempts are rate limited.
Connector secrets
Access tokens are envelope-encrypted: a random data key encrypts the secret, and the key-encryption key wraps the data key. Errors strip URLs so a SimpleFIN access URL is not logged.
Read-only by construction
The connector interface has no write or trade method. Plaid is limited to the transactions product. QuickBooks is specified as the read-only accounting scope. Nothing in v1 requests a transfer or payment scope.
Audit log
Sign-in, imports, syncs, entity changes, and billing events are appended. The application role cannot update or delete audit rows.
Jobs
Syncs run through a Postgres-backed queue with retries, backoff, idempotency keys, and per-source rate limits. Imports dedupe on an external id.
Reports
A finalized report is hashed with SHA-256. Anchoring writes only that hash into an XRPL memo. It does not publish balances.
Before production data
- Run the app role, not the table owner, in every deployed environment.
- Put the key-encryption key in a managed secret store and rotate it with a re-encryption job.
- Turn on managed Postgres backups, point-in-time recovery, and private networking.
- Complete a SOC 2 Type I readiness review, then a Type II observation window, plus a penetration test before production Plaid.
- Keep trading, payment, and write scopes out of every connector review.