Security & Safety
Last updated: 15 October 2026 · Controls ledger v1.1 · live SA attestation →
This page is honest about what’s shipped and what’s not. Each control carries an SX-### code that maps straight to our internal ledger (ISO 27001:2022 Annex A, SOC 2 CC, POPIA sections) and to the exact file in the codebase. Nothing listed here is marketing — every item is verifiable, and the SA sovereignty posture is enforced by the server refusing to boot without it.
South African sovereignty — the residency contract
SENTRIX is operated as a residency contract, not best-effort. Every component that touches your personal information lands on infrastructure inside the Republic of South Africa — compute, database, edge, payments, email, SMS, secrets vault.
- SX-150 Compute hard-locked to Johannesburg. Our Fly.io configuration sets
only_regions = ["jnb"]. Fly refuses to schedule a machine outside JNB even if the region is under capacity pressure. If JNB is unavailable, we return 503 — we accept availability loss over residency loss.
- SX-151 Sub-processor residency registry. A machine-readable list of every sub-processor, where it lands data, and whether it is sovereign.
- SX-152 Boot-time refusal. If any required sub-processor fails SA attestation under
SA_SOVEREIGN_MODE=1, the server exits before binding a port. You can’t accidentally run SENTRIX against a non-SA transit.
- SX-153 Public attestation endpoint.
GET /api/health/location — unauthenticated, returns the live sub-processor table any auditor can verify.
- SX-154 Email via KTH Mail (SA own-IP). SMTP host guard refuses anything that isn’t
.co.za / kth-mail / localhost under strict mode. No SendGrid, no SES.
- SX-155 SMS via Clickatell or Panacea Mobile (SA). Twilio US transit throws under strict mode rather than silently routing abroad. WhatsApp is disabled under strict mode — there is no SA-sovereign WhatsApp transit option today, so we refuse it rather than route via US.
Identity & access — shipped
- SX-010 Passwords never in plain text. bcrypt work factor 12 only. We cannot see or recover your password.
- SX-011 Short-lived access tokens. 15-minute signed JWT. Compromise window is minutes, not days.
- SX-012 Refresh-token rotation with replay detection. Reuse of a revoked refresh token nukes every refresh token for that user and forces reauthentication.
- SX-013 TOTP MFA. RFC 6238 time-based one-time passwords. Any authenticator app works.
- SX-014 SAML / OIDC SSO scaffold. Partial — schema and endpoint shape are in; first real enterprise round-trip pending.
- SX-015 Role-based access control. Ten roles, least-privilege, enforced on the server for every request — never relying on the UI.
- SX-016 Row-level security. Postgres RLS policies on
projects, risks, budget, and contracts. A query that forgets its org_id filter still returns nothing.
Data protection & cryptographic provenance
- SX-030 TLS 1.3 end-to-end. Fly + Cloudflare both terminate on current TLS stacks only.
- SX-031 Encryption at rest (AES-256). Managed by Fly Postgres.
- SX-032 Field-level envelope encryption. Sensitive columns (risk notes, voice transcripts) are AES-256-GCM encrypted with a per-record data-encryption key, wrapped by a master key-encryption key held outside the database. A DB admin inspecting a row sees ciphertext.
- SX-034 Signed deliverables. Board packs and reports return with an SHA-256 digest and an Ed25519 signature in response headers (
X-Sentrix-Content-SHA256, X-Sentrix-Signature, X-Sentrix-Signer). Our signing public key is published through KLUIS so any recipient can verify a pack independently.
Audit & non-repudiation
- SX-050 Append-only audit log. Every material state change is logged with actor, action, entity, before/after diff, IP, user-agent.
- SX-051 SHA-256 hash chain. Each audit row carries the hash of its predecessor. Tampering with any row breaks the chain from that point forward.
- SX-052 Verifier endpoint.
GET /api/security/audit/verify walks the chain and returns {total, intact, first_bad}. If someone edited a row directly in the database, you can prove it in one HTTP call.
Incident response & governance controls
- SX-070 POPIA s.22 breach pipeline. Incidents move through open → contained → notified_regulator → notified_subjects → closed. The 72-hour clock is computed from
discovered_at; overdue incidents are visible on the posture snapshot.
- SX-071 Regulator notification letter template.
GET /api/breach/:id/template produces the plain-text POPIA Information Regulator notice.
- SX-072 4-eyes principle. Destructive admin operations (delete org, delete user, bulk export, purge project, reset MFA, rotate secret) require a second admin to approve, with a minimum 20-character justification and a 24-hour auto-expiry. Proposer and approver cannot be the same person.
- SX-073 CSP violation ingest. Browser Content-Security-Policy violation reports stream into the platform and surface on the posture dashboard.
- SX-074 Security posture snapshot.
GET /api/security/posture — MFA coverage %, open breaches, pending 4-eyes approvals, 30-day audit events, 7-day CSP violations.
Transport headers (static site)
- SX-090 HSTS 2-year + preload.
max-age=63072000; includeSubDomains; preload.
- SX-091 Isolation headers. X-Frame-Options DENY, Cross-Origin-Opener-Policy same-origin, Cross-Origin-Embedder-Policy credentialless, Cross-Origin-Resource-Policy same-origin.
- SX-092 CSP enforce + CSP Report-Only strict side-by-side. The strict policy runs in Report-Only mode so we can measure what inline scripts would break before tightening enforcement.
- SX-093 Permissions-Policy locked. Camera, microphone, geolocation off by default.
- SX-094 Report-To group. CSP violations post to
https://api.sentrix-pmo.com/api/security/csp-report.
Webhooks & rate limiting
- SX-110 Paystack HMAC-SHA512. Every incoming payment webhook is signature-validated against the Paystack secret before it touches the database.
- SX-111 Twilio HMAC-SHA1. Validated the same way for the SMS / WhatsApp webhook (even when the gateway itself is disabled under strict mode).
- SX-130 Global rate limit. 500 requests per 15 minutes per IP across the API surface.
What’s still on the roadmap
Honest list — not shipped yet:
- Externalising the last inline
<script> tags so CSP enforce can drop 'unsafe-inline' entirely (ETA 2027-02).
- Automatic JWT_SECRET and SIGNING_KEY rotation via a KLUIS 90-day cron (ETA 2027-01).
- Live SSO round-trip with a first enterprise IdP (on first qualifying sale).
- Dependency vulnerability scanning in CI (
.github/workflows/security.yml — this week).
- mTLS between the API tier and Postgres (ETA 2027-03).
- Independent third-party penetration test and public remediation report.
- SOC 2 Type II / ISO 27001 certification — these require external audit cycles over time; we do not claim them today.
Using SENTRIX safely — decision support, not decisions
- AI insights are guidance, not verdicts. Forecasts come from your data via transparent rule-based logic; they are probabilistic and inform a human decision.
- Project Fingerprint™ is benchmarking, not a guarantee. Comparable precedents help you learn — they do not predict outcomes.
- Keep a human in the loop. SENTRIX takes no automated action with legal or financial consequence on your behalf. Budget, contracts, escalations stay yours.
- Your data drives your results. Treat outputs as one input to good governance, alongside your own judgement and controls.
Documents an auditor can ask us for
- Data Protection Impact Assessment (DPIA) — POPIA s.17.
- Records of Processing Activity (ROPA) — 11 named processing activities with retention, lawful basis, and sub-processor mapping.
- Security Controls Ledger — the SX-### register this page summarises, mapped to ISO 27001 Annex A, SOC 2 CC, POPIA.
- SA Sovereignty Attestation guide — how we enforce residency, and how to verify it yourself from
/api/health/location.
Email sentrix@kth-tech.com with the subject “Due Diligence” and we return the full pack within one business day.
Responsible disclosure
Found a vulnerability? Email sentrix@kth-tech.com with the subject “Security Disclosure” and enough detail to reproduce. We acknowledge, investigate, and keep you updated. No legal action against good-faith researchers who avoid privacy violations and data destruction and give us reasonable time to fix.
Incident & breach response
Compromise affecting personal information triggers the pipeline described above (SX-070 / SX-071). The Information Officer coordinates response — contact details in the Privacy Policy.
Questions
Anything else — security, safety, data protection — email sentrix@kth-tech.com. See also our Privacy Policy and Terms of Service.