Security

Security design. Three rules, all verifiable.

Three rules drive the design: we never store a secret we don’t need, staff never see request content, and every sensitive action is recorded in an audit log you can verify.

This is the design of the platform being built now. We will have it verified by an external penetration test before the first client goes live.

Minimal secrets
Keys shown once and stored as an HMAC; provider credentials only in Key Vault.
Content out of staff reach
No internal API returns prompts or responses.
Everything is written down
Append-only, hash-chained audit log you can verify and export.

API keys. Shown once, never recoverable.

Format situ_live_<public id>_<secret> (and situ_test_ for the sandbox). The secret carries at least 256 bits of entropy.

We store only HMAC-SHA256(pepper, secret). The pepper lives in Azure Key Vault (Managed HSM) and is versioned, so it can be rotated without invalidating existing keys.

Every key belongs to a project, has a mandatory expiry and an optional model allowlist. Revocation reaches every gateway replica within about a second.

Tenant isolation. Enforced by the database.

Every tenant table carries org_id and Postgres row-level security with FORCE ROW LEVEL SECURITY: not even the table owner can bypass it.

Each console request runs in a transaction that pins the active organisation; the database is the last line of defence, not the application.

The back office uses a separate database role. Every read of another organisation requires a stated reason and writes a record into that organisation’s audit log.

Content. Metadata only by default.

We record who, which model, how many tokens, cost, latency and status. Prompts and responses are not stored.

If a project turns on content logging, it is encrypted with AES-256-GCM under your organisation’s data key, with 0–365 days of retention. Deleting that key makes the content unreadable (crypto-shredding).

Zero-retention routes exist only for models whose provider supports it, and the console shows which ones do.

Audit log. A hash chain that reveals any tampering.

The audit log and the credit ledger are append-only: the application role has no UPDATE or DELETE.

Each row stores the hash of the previous one, computed by the database itself. You can check the chain from the console and export it as JSONL to verify it yourself.

Every mutating operation writes its record in the same transaction. Never with secrets. You can also stream the log to your SIEM over HTTPS.

Example chain
  1. #1041 project.update user prev 9c2e…71ab hash a3f1…0d42
  2. #1042 api_key.create user prev a3f1…0d42 hash 5b7c…e913
  3. #1043 admin.read staff prev 5b7c…e913 hash d08e…42fa

Staff and back office. No standing privileges.

The back office is reachable only from a private network, with Microsoft Entra ID SSO and hardware security keys, separate from customer identity.

No standing privileges beyond read-only metadata. Elevated roles are granted just in time, for at most 12 hours, through an approved request.

Four-eyes approval — the requester cannot approve, enforced by a database constraint — to suspend or reinstate organisations, adjust credit, change credit limits or billing mode, touch provider credentials, reset a user’s second factor and grant elevations.

Supply chain. What runs, signed and traceable.

Container images signed with cosign, an SBOM per release and pinned dependencies. Provider adapters come from Bifrost (Apache 2.0) at a pinned, audited release.

SAST, DAST and dependency scanning in CI. Security-critical code — auth, keys, tenancy, billing — needs a second human reviewer.

We disable any feature that fetches customer-supplied URLs: a gateway that fetches them is an SSRF vector inside our network.

Residency attestation. Every response carries its own evidence.

For every request, the gateway signs with Ed25519 which route, provider, region and tier served it. The private key lives in Azure Key Vault; the public keys are published so anyone can verify without asking us.

Token header
{ "alg": "EdDSA", "typ": "situra-residency+jwt", "kid": "7c1e…a90b" }
Signed claims
{
  "iss": "gw-spaincentral-…",
  "rid": "req_8354f6fb…",
  "iat": 1790391273,
  "org": "…", "prj": "…", "kid_pub": "…",
  "model": "gpt-5-mini",
  "route": "…",
  "provider": "azure-openai",
  "region": "spaincentral",
  "residency": "es",
  "project_residency": "es",
  "attempts": 1
}
Ed25519

sign(base64url(header) + "." + base64url(claims))

Signed claims
ridRequest id (same as x-request-id)
iatIssued at (Unix seconds)
issGateway instance that routed the request
org · prjOrganisation and project
kid_pubPublic part of the API key used (never the secret)
modelModel the client requested
route · provider · regionCatalogue route, provider and region that served the request
residencyTier of the route that served it: es, eu or global
project_residencyTier the project required
attemptsRoutes tried (fallbacks never leave the allowed tier)

What it proves

  • Which route, provider and region served that specific request, and at which residency tier.
  • That Situra’s gateway says so, with an Ed25519 signature anyone can check without trusting us or the console.
  • That the token has not been altered: changing a single character breaks the signature.

What it doesn’t prove

  • What happens inside the model provider: that rests on the provider’s regional commitments and its sub-processor contract.
  • It is a statement signed by Situra, not a third-party certification.

Verify it yourself

Public keys are published as a JWKS (OKP, Ed25519) at https://api.situra.ai/.well-known/situra-attestation-keys. The same token is stored with the request’s metadata, so it shows up in the console and in audit exports.

Terminal
# 1. Make a request and keep the header
curl -sD - -o /dev/null https://api.situra.ai/v1/chat/completions \
  -H "Authorization: Bearer $SITURA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-5-mini","messages":[{"role":"user","content":"Hola"}]}' \
  | grep -i '^x-situra-attestation:'

# 2. Fetch the gateway’s public keys
curl -s https://api.situra.ai/.well-known/situra-attestation-keys

External verification. What third parties will check.

External penetration test
Before the first client goes live; then yearly and after major changes.
Isolation tests
Automated tests proving that cross-tenant reads fail.
ENS + ISO 27001 audit
Joint certification audit targeted for Q2–Q3 2027.

Customer identity

A mandatory second factor before any organisation data: a passkey (WebAuthn) or TOTP, with recovery codes. Each organisation can require phishing-resistant MFA (passkeys only). Resetting a user’s second factor needs the approval of two Situra staff members. Console sign-in uses the platform’s OIDC login, with SCIM provisioning restricted to verified domains. SSO with your organisation’s identity provider (OIDC, and SAML through an IdP such as Zitadel): planned.

Responsible disclosure

If you find a vulnerability, write to before making it public. We answer in Spanish or English. The policy is published in security.txt.

Private beta · Q4 2026

We are looking for three to five organisations for the beta.

Spanish public administrations and regulated organisations that want to use AI models with data residency under control. We work with each organisation on ENS categorisation, the DPA and the integration.