Security posture

Security as it actually runs.

This page is a control inventory, not marketing copy. Each row below is something running in production today. The gaps section is what is not yet in place and when we plan to address it. Last reviewed 18 May 2026.

Caltury
Posture summary
Hosting
Sydney, AU
App + DB
Vercel + Supabase Pro
In transit
TLS 1.3
At rest
AES-256
Tenant isolation
Postgres RLS
MFA
TOTP available
Audit retention
7 years append-only
Audit chain
SHA-256 verifiable
Off-platform backup
S3 object-lock 7yr
Region
Sydney
At rest
AES-256
In transit
TLS 1.3
Isolation
RLS-scoped
Retention
7 years
Auth
MFA + branded mail

Published documents

Read the detail.

Incident response

Documented plan. Severity-tiered SLAs (P0 acknowledged within 1 hour, 24/7), OAIC NDB path, public status commitment.

Read the IR plan
Live status

Founder-maintained incident log. Updated within 1 hour of any P0 or P1. Machine-readable feed at /api/status.

See status
Self-audit, May 2026

OWASP ASVS Level 2 self-review. Per-control status, evidence, honest section on what self-audit cannot prove.

Read the audit

What runs in production

Control inventory.

Grouped by category. Every line is a control configured today in production. Supabase + Vercel, both Sydney region. Specific implementation references (project IDs, migration timestamps, policy numbers) are available to procurement on request.

01

Hosting and residency

All application data sits in Australia. Sub-processors outside AU are limited to identity verification, sanctions matching, AI text generation and transactional email.

Database, ap-southeast-2 (Sydney)
Supabase Postgres on the Pro plan, Sydney region. All organisation, user, customer, KYC, sanctions, SMR, TTR, IFTI, audit and retention records live here.
Application, Sydney region
Next.js on Vercel with the syd1 region pinned in vercel.json so edge functions execute in Sydney rather than the nearest Vercel POP.
Identity documents, never on Caltury
Stripe Identity (US / Ireland) holds raw ID images. Caltury stores the verification result and a Stripe reference only. We do not see, transit or persist the underlying image.
Sanctions matching, OpenSanctions (EU)
Customer name + DOB sent over TLS to OpenSanctions (Germany). Match results returned and stored in Caltury. Raw query not retained at OpenSanctions per their policy.
Transactional email, Resend (US)
Sign-up confirmations, magic links, KYC links, reviewer invites. Recipient address logged at Resend for deliverability telemetry; bodies not retained.
AI text generation, Anthropic (US)
SMR narrative drafts and structured intake helpers. Raw ID documents never sent. PII is the structured intake the user typed, not document images.
02

Encryption

AES-256 at rest via the Postgres TDE managed by Supabase. TLS 1.3 in transit everywhere. Stripe Identity uses its own encryption per its policy.

At rest, AES-256
Postgres TDE on the Supabase Pro plan. Object storage (file uploads, e.g. reviewer evidence) inherits the same at-rest encryption.
In transit, TLS 1.3
All client traffic, all server-to-server traffic, all sub-processor traffic.
Identity documents, Stripe-encrypted
Documents are encrypted in transit and at rest by Stripe Identity. Caltury never holds the key material because Caltury never holds the document.
03

Access control

Postgres row-level security on every public table. Org-scoped policies on every customer-data table. DELETE permission revoked on every audit-bearing table so soft-delete is the only path.

Row-level security on every public table
The database itself refuses to serve another org's data. A code bug cannot leak across tenants because the policy is enforced below the application.
Service role gated for audit inserts only
Service-role key is reserved for audit-log inserts so end users cannot forge audit rows. No service-role read paths exposed to client code.
DELETE revoked from authenticated role
On customers, kyc_verifications, sanctions_checks, smrs, ttrs, iftis, customer_transactions, customer_notes, audit_log, retention_schedule, risk_assessments, aml_programs, annual_reviews, annual_compliance_reports, reviewer_invites, user_invitations, customer_invites, training_records. Soft-delete via archived_at is the only path.
Role-based feature gating
Roles: owner, compliance_officer, staff. Settings, billing and sensitive AUSTRAC actions gated on owner / compliance_officer in middleware and at the policy layer.
04

Authentication

Supabase Auth with email / password, magic link and Google OAuth. TOTP MFA available. Branded auth emails from a Caltury sender via Resend SMTP.

Email / password, magic link, Google OAuth
Three sign-in paths. Email / password uses Supabase's bcrypt-hashed credentials. Reset over a verified single-use token.
TOTP multi-factor authentication
Users can enable TOTP at /dashboard/settings/security. Compatible with Authy, 1Password, Google Authenticator and any RFC 6238 app.
Branded auth emails from support@caltury.com.au
Auth notifications sent via Resend SMTP rather than default supabase.co. Configured May 2026 via the Supabase management API.
Sign-up rate limiting
Per-IP throttle on sign-up, backed by Upstash Redis when configured. Failed sign-in attempts surface in Supabase Auth logs.
APP 8.2(b) overseas-disclosure consent
Captured at sign-up and recorded in an append-only consent ledger. Users see the named sub-processors and consent before account creation.
05

Token security

Every long-lived token issued by Caltury is SHA-256 hashed at rest. Cleartext is shown once at issuance, then irretrievable.

Reviewer invite tokens, hashed at rest
Cleartext shown once to the inviter, then only the SHA-256 hash is persisted. Lookups go via constant-time hash comparison.
User invitation tokens, hashed at rest
Same shape: cleartext at issuance, hash at rest.
Customer invite tokens, hashed at rest
Cleartext id replaced with a hashed token. Public lookup goes through a server-side function with elevated privileges rather than a direct anonymous select.
Calendar feed tokens, hashed at rest
iCal subscription URLs use a hashed token so a leaked URL can be rotated without exposing the user's whole feed history.
06

Audit and retention

Append-only audit_log on every state-changing action with a SHA-256 hash chain verifiable via /api/audit/verify. 7-year retention per AML/CTF Act ch 11, enforced by per-record retain_until dates. Records never auto-deleted.

Append-only audit log
No DELETE policy. No UPDATE policy. Inserts go via service role so authenticated users cannot forge rows. 25+ event types cover every state-change action across enrolment, KYC, sanctions, SMR / TTR / IFTI, training and reviewer workflows.
SHA-256 hash chain on every row
Migration 0067 added payload_hash + prev_hash + row_hash columns to audit_log. A BEFORE INSERT trigger fills all three on every insert path so every code path is covered; a per-org advisory lock serialises concurrent writes so a chain cannot fork. The chain is partitioned per org (migration 0073): each org's rows form an independent chain from the all-zero sentinel, so the audit log inside your data export is a complete, self-contained chain you can verify standalone — no other org's rows are needed. Any post-hoc edit invalidates the row's hash and every subsequent link in that org's chain. GET /api/audit/verify walks every org chain from the sentinel and recomputes every hash; the verifier source in lib/audit/hash-chain.ts is lift-and-reproduce.
7-year retention, enforced per record
Each record carries a retain-until date. Live records stay live for the full window. The vault flags rows that cross 7 years for manual review; nothing auto-deletes.
Retention clock respects end-of-relationship
On customer archival the retention clock extends so the start point is the later of record creation or end-of-relationship, per the Act. Applies to SMRs and TTRs as well as customer records.
Tipping-off-aware exports
SMR-related audit events are redacted from CSV export by default (s.123 tipping-off mitigation). An explicit ?include_smr=1 opt-in is required to include them.
07

Backups

Daily Supabase snapshot with point-in-time recovery. Weekly off-platform backup to a Caltury-owned S3 bucket in Sydney with object-lock compliance mode and 7-year retention. Live records remain the source of truth for the full 7-year compliance window.

Daily Supabase snapshot with PITR
Supabase Pro default: 7-day rolling snapshot window plus point-in-time recovery to any second within that window. Snapshots stored in Supabase-managed S3 in Sydney, encrypted at rest.
Weekly off-platform backup with object lock
Vercel cron at /api/cron/off-platform-backup runs every Sunday 04:00 UTC. Streams every compliance-bearing table (customers, KYC, sanctions, SMR / TTR / IFTI, transactions, training, audit_log including hash-chain columns) to NDJSON, gzips, and uploads to a Caltury-owned S3 bucket (ap-southeast-2 Sydney) with object lock in compliance mode and 2,557-day (7-year) retention. Compliance mode means not even the AWS root account can delete or shorten the lock before expiry. Per-backup metadata (etag, payload SHA-256, lock-until date) is recorded in the off_platform_backups table (migration 0068).
Compliance records live, not backup-only
The 7-year AML/CTF retention obligation is met by the live audit log and retention schedule. Backups (Supabase daily plus the weekly off-platform copy) are disaster-recovery insurance, not the primary compliance record.
08

Web security

Browser-side hardening set in next.config.ts. HSTS preload, a CSP locked to the named upstreams, and the usual clickjacking + MIME-sniff defences.

HSTS, preload-ready
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload. Browsers refuse cleartext for two years.
Clickjacking and MIME protection
X-Frame-Options: DENY. X-Content-Type-Options: nosniff. Referrer-Policy: strict-origin-when-cross-origin.
Permissions-Policy locked down
Camera, microphone, geolocation and the interest-cohort opt-out all disabled at the policy header.
Content-Security-Policy on known upstreams
script-src, style-src, img-src, font-src and connect-src restricted to the named upstreams (Stripe, Supabase, OpenSanctions, Anthropic, Resend). No wildcards, no inline-eval shortcuts.
09

Operational hygiene

Error monitoring with PII scrubbing, idempotent webhooks, per-org cron checkpointing, CSV formula-injection escaping, and a public health endpoint.

Sentry with recursive PII scrubbing
Email, ABN, DOB, address, name, passport and drivers_licence redacted from event extras, tags, contexts, breadcrumbs and request data before they leave the SDK. Release tags pinned to VERCEL_GIT_COMMIT_SHA so errors map to a specific commit.
Stripe webhook idempotency
A dedicated event-id ledger tracks every Stripe webhook event id. Replays are no-ops.
Cron checkpointing per org
A mid-run failure does not starve later orgs because the cron resumes from the last checkpointed cursor.
CSV export formula-injection escape
Leading =, +, -, @, tab and CR characters are prefixed with a single quote so a malicious customer-typed value cannot become an Excel formula in an exported file.
/api/health endpoint
Public health endpoint for uptime monitors. Returns status and version, no internal detail.
Resend bounce / complaint webhook
Deliverability problems (hard bounce, complaint) are captured to Sentry so silent loss of an SMR or reviewer email surfaces fast.
10

Compliance-engine controls

Controls specific to running an AML/CTF reporting workflow correctly. These are AUSTRAC-domain rather than infrastructure but they protect compliance evidence.

Daily sanctions re-screen, Founding 5
Vercel cron runs daily across the Founding 5 rosters. New matches email the owner / CO; a Friday digest summarises the week. Founder action not required.
OCDD cadence cron
Risk-rated re-screen: 3 years for low, 1 year for medium, 6 months for high. Driven by per-customer ocdd_next_due_at, scheduled centrally.
Independent review enforcement
The annual review wizard requires linked reviewer findings within 13 months or a documented skip reason before the review can be signed off.
Beneficial owner schema enforcement
Trust requires trustee + settlor + beneficiary. Partnership requires every partner attested. Company requires director + a qualifying owner. The KYC flow refuses to mark complete otherwise.
TF SMR 24-hour deadline
When the terrorism financing flag is set the SMR clock is 24 hours per chapter 41 of the Rules, rather than the standard 3 business days. Surfaces in the dashboard countdown.
Atomic Founding 5 slot claim
Slot claims go through an advisory-locked Postgres function so two simultaneous claims cannot both succeed.

Insurance

Cover bound 15 May 2026.

Caltury is insured via DUAL (broker BizCover). Certificates of currency available on request to support@caltury.com.au. Renewal 15 May 2027.

Professional Indemnity
A$1,000,000
Public Liability
A$20,000,000
Cyber Liability
A$1,000,000

What we do not have yet

Honest gaps.

Each gap below is real. Most are deferred to a triggering event (first enterprise customer ask, Pty Ltd conversion, government workload) rather than addressed speculatively. Asking for any of these in a security questionnaire will not surprise us.

SOC 2 (Type 1 or Type 2)
Underlying controls a SOC 2 auditor would test are in place. Formal audit deferred because no enterprise customer has required it yet. The audit is overhead, not a control.
First enterprise ask
ISO 27001
Same posture as SOC 2. Useful when selling to large enterprises or EU customers; not currently a buying criterion for the Tranche 2 ICP.
First enterprise ask
IRAP assessment
Required for Australian government workloads. Triggered if a government workload is in scope.
Government workload
External CREST penetration test
Not yet performed. In the meantime: OWASP ASVS Level 2 self-audit at /security/audit-2026-05, weekly Dependabot dependency alerts, a published RFC 9116 disclosure policy at /.well-known/security.txt, and customer-initiated pen tests coordinated in writing at no charge. External CREST-accredited test scheduled at first enterprise customer or 1 January 2027 whichever sooner.
Enterprise customer or 1 Jan 2027
Bug bounty programme
Coordinated email disclosure to security@caltury.com.au, policy published at /.well-known/security.txt per RFC 9116. P0 reports acknowledged within 1 hour 24/7, anything else within 8 business hours. Cash awards may follow once an enterprise customer is on the books.
Post-pentest
Data subject access request automation
Manual today. A user can self-serve a full APP-12 data export from /dashboard/settings/data. Caltury runs the deletion path manually on written request.
When volume warrants
Sub-processor change notification
Today, sub-processor changes are surfaced through Privacy Policy versioning at /privacy. A dedicated email notification list is not yet stood up.
First enterprise ask
Human-lawyer review of Privacy Policy + Terms
Privacy Policy v5 and Terms of Service v4 were drafted and reviewed with AI assistance via LawPath Atlas, not a human solicitor. Formal counsel review planned before the first enterprise deal or at Pty Ltd conversion, whichever lands first.
Pty Ltd or enterprise deal

For procurement and pen testers

Working with us, async.

Caltury runs async over email. We do not do screenshares, calls, video demos or webinars for security review. Everything below happens in writing so you have a record.

Control inventory

Email for the current control inventory as a signed PDF, mapped to the SIG-Lite question set. Usually returned within a few business days.

support@caltury.com.au
Penetration test + disclosure

Coordinated disclosure policy at /.well-known/security.txt per RFC 9116. Customer-initiated pen tests coordinated in writing at no charge — reach out with scope, intended dates, source IPs, and rules of engagement. Reports stay between you and us.

security@caltury.com.au
Policy documents

Privacy Policy v5, Terms of Service v4, and the Notifiable Data Breach response plan are available on the live site and over email. Sub-processor list is published at /sub-processors.

Privacy policy

Questions on any specific control?

Email support@caltury.com.au.

Founder Ben Horne replies in writing, usually within a few business days. No calls, no demos.