Security
This page consolidates the security claims the landing page makes into one document procurement teams can read in a single sitting. Each item is tagged honestly: shipped means the runtime enforces it today and it's customer-verifiable; partial means it's enforced for the listed scope but has named exclusions; roadmap means committed-direction but not yet shipping.
Deeper reading — audit-ready evidence
Three companion documents, all in draft as of the "Last updated" date above, all served as raw markdown so the source of truth stays under version control:
- /security/trust — customer-facing security narrative. What we ship, what YOU can verify without trusting us, what we don't yet ship, honest comparison to SOC 2, contact + escalation. Written for a CISO reading a vendor page.
- /security/threat-model — enumerated threat scenarios, each mapped to specific controls with file + line citations, and explicit residual risks. Written to hold up under external cryptographic review.
- /security/verify
— five-minute walkthrough for verifying a receipt bundle
against our substrate's cryptographic claims. Offline, no
network, no trust required in our servers. A hash-consistent
fixture bundle ships at
/security/verify/fixture/bundle.json; clone the CLI, runcirca verify --bundle, get a green result in seconds.
Note: /trust is a separate, live transparency
dashboard (uptime, hash-chain checkpoints, continuous probes,
advisories). The three docs above are architectural + verifier
material; /trust is operational state.
Data at rest shipped
- HMAC secrets sealed under a per-process Data Encryption Key (DEK) using AES-256-GCM. Sealed envelope is what sits on disk; cleartext lives only on the process stack during a verify operation. A stolen disk yields ciphertext only.
- X25519 per-customer envelope encryption on every audit-log row: row content is encrypted to the customer's public sealing key at write time. We can't decrypt rows we just wrote. Customers receive their X25519 private PEM once at issue time and hold it themselves.
- Hash-chained audit log per
(tenant, app_id). Each row carriesprev_hashandrow_hash; mutation of any historical row breaks the chain visibly. Customers verify their own slice viaGET /v1/auditand can computerow_hashoffline using the published canonical-JSON rule (whitepaper §4). - API key storage: bearer keys are hashed with SHA-256 before persistence; the plaintext is shown to the customer once at issue time and never persisted server-side.
Data in flight shipped
- TLS 1.2+ mandatory for every endpoint, terminated at the nginx ingress with a certificate issued by Let's Encrypt (90-day renewal cycle, auto-renewed via certbot).
- HSTS preload declared
(
max-age=63072000; includeSubDomains; preload). - Content-Security-Policy on every HTML response denies inline scripts, restricts form-action to Stripe checkout, and pins frame-ancestors to none.
- No third-party CDN for first-party assets — all customer-facing HTML is served directly from the runtime. Zero third-party JavaScript trackers.
Per-response cryptographic receipts shipped
Every /v1/* response carries two independent receipts that
bind the response to the running build and the audit chain head:
-
HMAC tamper signature — header
X-Cogos-Signature(algorithm inX-Cogos-Signature-Algo, currentlyhmac-sha256). Computed over the canonicalized response body using a per-key shared secret returned to the customer at key issue time. Customer recomputes locally and compares; any divergence proves the response was altered in flight. -
Ed25519 attestation receipt — header
X-Cogos-Attestation(algorithm inX-Cogos-Attestation-Algo, currentlyed25519). A signed token whose payload commits to the request hash, response hash, running build version, and the audit-chain head as of the response. The signing public key is published at /attestation.pub and rotates each container restart; the key ID is in the token. A customer who archives attestations on a cadence can prove later that the chain was not rewritten between two anchor points.
Inference path shipped
- No third-party hosted LLM in the request path. Inference is substrate-resolved on first-party infrastructure (AWS EC2, our account). The single external dependency on the substrate path is the optional live-search provider, declared per-call in the audit row.
- Loopback-bound substrate. The LLM serving process listens only on the loopback interface; only the gateway on the same host can reach it. No public ingress to the model.
Image supply chain roadmap
- cosign-signed container images + admission gate + distroless runtime are on the roadmap. The current AWS deployment runs the gateway as a systemd service from source on the host; signed container builds and verification-at-start were dropped in the 2026-06-20 Azure→AWS cutover and have not been restored. The audit log + receipt mechanisms operate identically regardless of the deploy mechanism.
Customer authentication shipped
- Bearer keys with the format
sk-cogos-<hex32>. Rotated perPOST /v1/keys/rotatewith a 24-hour grace window; a leaked key auto-quarantines the moment a scanner pattern fires from the same IP within 60 seconds of an authorized hit. - Optional Ed25519 keypair auth — customer
generates a keypair on their side, sends the public key to us,
signs each request with the private key. We hold no
re-usable customer secret. Issuance via the
scheme=ed25519param onPOST /admin/keys.
Cross-origin resource sharing (CORS) shipped
- Global CORS middleware allowlists an explicit set of origins:
https://5ceos.com,https://www.5ceos.com,https://app.5ceos.com,https://circaos.5ceos.com, plushttp://localhost:3000andhttp://localhost:3010for dev. Any otherOrigingets noAccess-Control-Allow-Originheader — browser blocks the response. - Applies to
/v1/*substrate,/dashboard,/enterprise-inquiry,/audit,/health, and/stratumpaths. Same-origin requests unchanged. - Preflight
OPTIONSrequests handled explicitly withAccess-Control-Max-Age: 86400and a locked-down method / header allowlist (Authorization, Content-Type, X-API-Key, X-Admin-Key only).
Tenant isolation shipped
- Store layer:
commitment-store,contradiction-store, andfindings-storeall throwError('tenant_id is required')on missing tenant.readForTenant({tenant_id})returns[]on missing tenant — never "all rows." Impossible to cross-tenant via forgotten filter. - Session layer:
/dashboard/homefilterskeys.list()explicitly byreq.session.tenant_id(load-bearing comment on the line). Session cookies are HMAC-signed with a persistentCOGOS_SESSION_SECRET— a forged cookie won't verify. - API-key layer:
tenant_idis sourced fromreq.apiKeyafter key verification — never client-supplied. A customer cannot pass atenant_idin the body or query and have it honored; the server-side auth binding is authoritative.
Hash-chain checkpoint anchoring shipped
- Global hash-chain head published at
/audit/checkpoint/latest
(JSON:
ts,global_head,prev_global_head,partition_count,row_hash). Every per-tenant audit chain rolls up into this global head each cycle. - External Bitcoin-backed anchoring via OpenTimestamps.
Each global checkpoint is periodically anchored to
alice.btc.calendar.opentimestamps.org,btc.calendar.catallaxy.com,finney.calendar.eternitywall.com, anda.pool.opentimestamps.org. Anchors are retrievable at /audit/checkpoint/anchors. Once anchored, the checkpoint's existence at that timestamp is provable independently of us — using bitcoin, not our word. - Third-party verification at
/audit/checkpoint/verify —
anyone can post a claimed
global_headand receive back the anchor status without authentication.
Runtime hardening shipped
- No
/adminendpoint advertised on the public surface; admin routes are gated byX-Admin-Keyand an explicit allowlist of operator-tier paths. - Rate limiting: per-IP and per-tenant token-bucket
limiters with separate buckets; per-tenant cap reads from the
package
rpm_limitfield so each tier carries its own ceiling. Free tier: 20 RPM. Business: 1,200 RPM. See SLA. - Per-package prompt-size ceiling
(
max_prompt_tokens_per_call) prevents per-request compute-cost abuse independent of monthly quota. - Continuous external probing — a Container App Job runs scheduled probes against this domain daily from a separate region, recording responses for the audit trail.
Key management partial
- Customer-facing keys (bearer secret, HMAC shared secret, X25519 sealing key) are issued once and held by the customer. We do not retain reusable customer auth material at rest after issuance for the ed25519 scheme; bearer scheme stores only the SHA-256 hash.
- Server-side signing keys (per-response Ed25519 attestation keypair) are generated in-process and rotated each container restart. The active public key is at /attestation.pub with the matching kid in the response header.
- Honest gap: we do not yet operate a customer- facing key vault for storing customer secrets in our envelope. If a customer needs key-escrow or HSM-backed storage of their own material, that's an enterprise-contract conversation today.
SOC 2 posture — what's actually happening now in progress
We name this section honestly. SOC 2 Type II attestation is not signed; that requires a third-party audit that hasn't been booked yet. But every control on the SOC 2 Trust Service Criteria (Security · Availability · Confidentiality) that we can execute pre-audit is either shipping, documented, or actively being built. This section is what we can defend to a security review that asks “so what have you actually done?”
Security TSC — substantially in place
- Access controls: per-tenant isolation enforced at the store layer (throw-on-missing); admin routes gated by separate credential; MFA on all operator third-party accounts (GitHub, AWS, Stripe).
- Change management: versioned-release deploys with
instant symlink rollback; TTY-gated production deploys with
typed confirmation tokens; backup of prior state on every substrate
deploy; deploy runbook documented at
docs/RUNBOOK-stratum-launch-2026-07-21.md. - Encryption in transit: TLS 1.2+ mandatory; HSTS preload; CSP on every HTML response; no third-party CDN.
- Encryption at rest: AES-256-GCM DEK-sealed HMAC secrets; X25519 per-customer envelope encryption on audit rows; SHA-256 hash of API keys, plaintext never persisted.
- Vulnerability management: gitleaks pre-commit hook
(blocks secret leaks in staged diff); deploy-denylist enforcement
(blocks bundling
.env*, uploads/, storage/, raw data); distroless runtime target on roadmap; continuous external probing from a separate region records daily response snapshots. - Logging & monitoring: hash-chained audit log per tenant + globally rolled up + externally Bitcoin-anchored; anomaly detector observes every request (shadow mode default, ANOMALY_FAIL_CLOSED=1 enables ban-tripping); per-IP + per-tenant + per-plan rate limiters.
- Perimeter defense: honeypot middleware intercepts scanner paths; CORS allowlist locked; substrate loopback-bound.
- Doctrine-locked emission: findings must go via AnomalyEmitter (doctrine test scans for direct writes); no unsanctioned write path.
- Incident response: disclosure email + acknowledgment SLA published on this page; rollback anchors preserved on every deploy; incident postmortem template on roadmap.
Confidentiality TSC — substantially in place
- Data classification: customer corpus, per-response outputs, and audit rows are all tenant-scoped; sealed-audit rows can only be decrypted by the customer's X25519 private key.
- Data retention: pilot corpus archived 60 days,
deleted on written request (per Stratum SOW); audit rows retained
per SLA. Documented data retention + destruction policy in
docs/policies/(planned; not yet published). - Sub-processor inventory: live at /sub-processors. Every third party that touches customer data is listed; changes require 30-day notice per DPA.
Availability TSC — being built
- Uptime monitor: BetterUptime free tier planned for deployment against this domain from external region (multi-region checks). Status page at status.
- Backups + DR: versioned releases enable instant rollback; formal RTO/RPO not yet documented. Cross-region snapshot cadence on roadmap.
- Capacity planning: per-tenant quotas prevent single-tenant compute exhaustion; per-tier package caps published in SLA.
Formal attestation path — committed, unbooked
- SOC 2 Type I — targeted engagement Q4 2026 via one of Vanta / Drata / Secureframe / Sprinto. Evidence collection starts before engagement booked; controls above are the evidence.
- SOC 2 Type II — sequenced ~6 months after Type I (standard observation window).
- Third-party pentest — pentest engaged before Type I audit; report shareable under NDA.
- ISO 27001 — sequenced after SOC 2 Type II lands.
- Enterprise pilots today — sign under our DPA + MSA; the substrate they use is the exact substrate the audit will attest against; they get the receipts + evidence chain that the audit relies on.
Responsible disclosure
Found a security issue? Email support@5ceos.com with the subject line "Security Disclosure". Include reproduction steps and an estimate of the affected tenants. We acknowledge within 1 business day, triage within 3 business days, and we'll keep you informed through the fix. We do not currently run a paid bug-bounty program; we publicly credit researchers in /trust advisories after the fix ships, with the researcher's permission.