- Policy / docs
Trust centre upgrade — Security Overview PDF, DPA template, sub-processor list
Published a downloadable Security Overview document, a customer-executable Data Processing Agreement template, and a sub-processor CSV. /trust now hosts the full vendor due-diligence pack.
- Security control
Migration v78 — clears P0 advisor ERRORs (RLS + search_path)
Tightened Row Level Security policies and pinned SECURITY DEFINER RPCs to a stable search_path. Cleared the priority-zero findings from the Supabase advisor security audit. Hygiene work for the long tail tracked in BACKLOG.
- Security control
Extension — per-install ECDSA P-256 signature with non-extractable keys
Browser extension requests are now signed with an ECDSA P-256 keypair generated locally with extractable: false. Public keys register through a Cloudflare Turnstile-gated endpoint with IP rate limiting. Replay protection enforced via Redis nonce SETNX with a 10-minute TTL aligned to the ±5-minute timestamp skew window.
- Infrastructure
Stripe webhook idempotency via stripe_event_log
Stripe webhook handler now deduplicates events at the database layer using an insert-with-conflict gate on event.id. Duplicate deliveries return 200 without re-running side effects.
- Security control
PII scrubbing — 12 patterns now cover AU mobile, BSB, TFN, and Medicare
Expanded the pre-storage PII scrubber to cover Australian-specific identifiers (Tax File Number, Medicare, BSB, AU mobile and landline). Order matters: more specific patterns run first to avoid generic phone-number masking shadowing them.
- Security control
CSP hardened — removed unsafe-eval, added frame-ancestors none
Content Security Policy at the edge now drops unsafe-eval, blocks framing entirely (frame-ancestors none + X-Frame-Options DENY), and enforces upgrade-insecure-requests. HSTS preload submission accepted for askarthur.au.
- Security control
Rate limiter — production now fails closed
Two-layer rate limiter (edge middleware + per-route burst+daily limits) returns 503 in production when Upstash Redis is unavailable, rather than allowing requests through. Local dev still fails open.
- Security control
Admin auth — HMAC cookie with 24h expiry replaces basic auth
Admin panel access migrated to a cookie-based HMAC scheme (SHA-256, 24h expiry, timing-safe comparison). Supabase admin role check sits in front as the primary auth path with the HMAC cookie as fallback for dual-mode operation.
Reporting a security issue
Email brendan@askarthur.au with reproduction steps. We triage within 24 hours and notify affected customers within 72 hours of confirming a breach.
Older entries are retained in SECURITY.md in the public repository.