Last updated 4 November 2026
This page describes what we do today, including what we do not yet do. For the contractual terms see the Data Processing Addendum and the subprocessor list.
Security at a glance
| Control | Status | Detail |
|---|---|---|
| Hosting | In place | Microsoft Azure commercial cloud. Compute in East US, database in Central US. Not Azure Government. |
| Encryption in transit | In place | TLS on every connection. |
| Encryption at rest | In place | Azure default encryption for the database and storage. Webhook signing secrets use AES-256-GCM. |
| API key storage | In place | Stored only as bcrypt hashes. A rotated key stays valid for 24 hours, and a key can be revoked at once. |
| Signed webhooks | In place | HMAC-SHA256 over the timestamp and body, HTTPS only, private addresses refused. Reject deliveries older than five minutes. |
| AI off switch | In place | Per request or for the whole account. A request cannot turn AI on for an account that turned it off. |
| Account separation of filings | In place | AES filings, authorizations and their documents are visible only to the account that owns them, with an audit log of who did what. |
| Idempotent retries | In place | Replayed for 24 hours. Keys are held on the instance that handled the request, so replay is best-effort. |
| Per-key scopes and IP allowlists | Not yet | Access is per environment and per subscribed API. Finer scopes and allowlists are not available. |
| US-persons-only access policy | Not yet | Not formalised. Contact us before sending export-controlled data. |
| SOC 2 Type I | Planned | Not yet completed. This page changes when a report is issued, not before. |
| Independent penetration test | Planned | Not yet done. |
| Business Associate Agreement | On request | Available after a security review. |
Details on each follow below. Anything marked planned or not yet is not in place today.
Hosting and location
- Microsoft Azure commercial cloud. Application compute runs in East US; the PostgreSQL database runs in Central US. We do not currently run in Azure Government (GovCloud).
- Data is encrypted in transit with TLS. The database and storage use Azure's default encryption at rest.
- Stored secrets (webhook signing secrets) are encrypted with AES-256-GCM. API keys are stored only as bcrypt hashes and cannot be retrieved.
- US-person access. We have not yet formalised a US-persons-only access policy for production systems. A US-only deployment tier and an Azure Government option are on our roadmap; if export-controlled data handling is a requirement for you, contact us before sending that data.
Data flow
One request travels through these stages:
- 1
Your system
HTTPS request with a Bearer token. Optional: Idempotency-Key, aiMode: off
- 2
API gateway (Azure Container Apps, East US)
TLS termination, key check, rate limits, idempotency replay, AI-mode decision, personal identifiers redacted from logs
- 3
Service
Screening, risk scoring, tariff, AES and lookup logic
- 4
List cache or source
Consolidated Screening List (synced copy, or live download), or a live query to a public source. The list version and retrieval time go into the response
- 5
Optional language model
Anthropic, only when AI is on for the request and account. Date of birth, SSN digits, passport and national ID numbers are removed before any prompt is built
- 6
Database (PostgreSQL, Central US)
Screening records and request logs with personal identifiers redacted; webhook signing secrets encrypted
AI processing and sensitive identifiers
- Send
"aiMode": "off"in the request body (or the headerX-AI-Mode: off) to forbid language-model processing for that request. Endpoints that cannot work without a model return403 AI_DISABLED. - An account-level setting turns AI off for every request made with your keys (Developer Portal, AI processing). A request can turn AI off but can never turn it back on for an account that disabled it.
- Date of birth, year and place of birth, SSN digits, passport and national ID numbers are used only for matching on our systems. They are removed before any prompt is built and are redacted from stored screening records and request logs.
- Zero-data-retention terms with the AI providers are not enabled today; see the subprocessor list.
Authentication and keys
- OAuth 2.0 client credentials (
POST /oauth/token) or a Bearer API key. Sandbox keys start withcg_sk_and production keys withcg_pk_; the two environments are separate. - Rotation. Rotating a key issues a new key and keeps the old one valid for a 24-hour grace period so you can deploy without downtime. A key can also be revoked immediately.
- Scopes. Access is granted per environment and per subscribed API. Per-key fine-grained scopes are not available yet. Administrative operations use a separate credential that is never issued to customers.
- IP allowlisting. Not available yet. We do not publish static egress addresses for webhooks either.
- Every response carries
X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Resetfor the tightest window that applies to you.
Safe retries and webhooks
- Idempotency. Send an
Idempotency-Keyon POST requests. The same key and body replays the stored response for 24 hours; a different body with the same key returns 422. Keys are held in memory on the instance that handled the request until a shared store is configured, so replay is best-effort across restarts and multiple instances. - Signed webhooks. Every delivery has
X-ComplianceGrid-Signature: t=<unix>,v1=<hex>, wherev1is HMAC-SHA256 of<t>.<raw body>with your signing secret. Reject deliveries older than five minutes. Deliveries are retried twice on network errors and 5xx responses. - Webhook URLs must be HTTPS. Private, loopback, link-local and cloud-metadata addresses are rejected, credentials in URLs are rejected, and redirects are not followed.
const crypto = require("crypto");
// rawBody must be the exact bytes received, before any JSON parsing
function verifyWebhook(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
const age = Math.abs(Date.now() / 1000 - Number(parts.t));
if (!parts.t || !parts.v1 || age > 300) return false; // reject stale deliveries
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Screening records and data freshness
Screenings made with your production keys are stored with the request (personal identifiers redacted), the result, the list version and retrieval time, and any reviewer decision, and can be retrieved with GET /v1/screenings and GET /v1/screenings/:id. Records are kept until you ask us to delete them or your account is closed. Every screening and risk response includes listVersion and listRetrievedAt; use those, not marketing language, to judge freshness.
Assurance status
- We do not yet have a SOC 2 report. A SOC 2 Type I audit is planned with an external auditor.
- We have not yet had an independent penetration test. One is planned with an external firm.
- A Business Associate Agreement is available only after a security review. Contact sales to start one.
We will update this section when those milestones are reached, not before.
Report a vulnerability
If you believe you have found a security vulnerability in ComplianceGrid, email security@compliancegrid.ai. Our contact details are also published at /.well-known/security.txt.
- Include what you found, how to reproduce it and the impact. Encrypt with the contact in security.txt if you prefer; do not include other people's data.
- Please do not access, modify or retain data that is not yours, degrade the service, or run automated scanners at high volume. Test against the sandbox where you can.
- We aim to acknowledge reports within three business days and to keep you informed until the issue is resolved.
- We will not pursue legal action against good-faith research that follows this policy. This commitment is pending legal review.
- We do not currently run a bug bounty programme and cannot offer payment.