Security
Last reviewed: August 12, 2026.
This page covers the per-org security controls surfaced in the Settings → Security pane, and it carries the authoritative statement of the Zero Data Retention boundary. Live in production today: the Zero Data Retention setting, the anomaly rate-limit that caps how loudly the detector can fire, and the access scoping that gates every admin surface. Two controls are on the roadmap and documented here as designed, not yet live: the PII redactor inline path that would strip sensitive content out of the prompt before it leaves the gateway, and the multi-region data-residency control that would pin the org's region to matching providers.
The audience is an org admin tuning security plus data-residency posture. Each section names the control the admin flips, the gateway behaviour the flip changes, and the roadmap work that will close the section out.
Zero data retention
Status: Live today. Per-org Zero Data Retention is in force in production and is self-serve on every plan, including Free.
Zero Data Retention (ZDR) is an org-level setting, flipped by an owner or an admin from the Settings pane, and it takes hold on the very next request. When it goes on, the gateway stamps an enablement timestamp server-side, so you have a fixed, non-client-supplied date from which the boundary below applies. This section is the authoritative statement of that boundary, written so you can hand it to your own security reviewer without paraphrasing it first.
The retention boundary
With ZDR on, payload logging and telemetry content retention are disabled and locked for your org. Request and response bodies are never written to durable storage: not to the requests browser, not to the audit trail, not by any operational record the gateway keeps. The lock is a real lock rather than a default, so an attempt to arm payload capture while ZDR is on is rejected outright with a 400 instead of being quietly honoured, and an already-open capture window is closed by the same flip rather than merely being blocked from renewing. The routing judge's free-text reasoning, which is the one remaining place a fragment of your content could have surfaced inside an operational record, is withheld from telemetry as well.
Conversation state on the stateful API still exists, because that API cannot function without it, but it exists only to operate that API and it is bounded by a time-to-live. An idle conversation expires automatically, 24 hours by default, and an org-level erasure sweeps your conversations immediately rather than waiting for the TTL to run out. Nothing outside that mechanism keeps a copy.
Response caching remains active under your org's configuration, and this is stated here plainly rather than buried, because a reader who assumes ZDR means nothing is stored anywhere would be wrong. ZDR does not turn caching off. Cached responses are org-isolated, carry short TTLs, and keep serving while ZDR is on. If you want caching off, turn caching off; ZDR is a separate control.
Finally, ZDR does not mean nothing is stored. Metadata rows keep recording, meaning timing, token counts, cost, and which model was chosen, because billing and the usage page run on exactly those rows. Your content is not in them, but they are written and retained, and any claim that the gateway stores nothing at all for a ZDR org would be wrong.
What flipping it back off does
Turning ZDR off removes the lock and lets payload capture be configured again. It does not restore, backfill, or reconstruct anything that was never written while the lock was on. In the same way, turning ZDR on is forward-only: it stops new content from being recorded, and it does not reach back and delete payloads captured before the enablement timestamp. If you need those removed, use the erasure path rather than assuming the flip did it for you.
PII redactor inline path
Status: Roadmap. The gateway PII redactor described in this section is on the roadmap; it is not live at the request boundary in production today. The section documents the per-org control surface as it is designed.
The PII redactor is designed to run inline on the request path so an org with the inline flag enabled redacts the prompt before it leaves the gateway, then re-injects the original spans on the response stream so the model's reply still references the user's actual data.
The two flags
The redactor reads two per-org settings:
- A redaction mode: one of
off,redact_in_transit, orredact_and_log.offskips the redactor entirely. - An inline-enabled gate. The redactor only runs when the mode is
not
offAND inline is enabled.
The two-flag design lets an org stage the rollout: set the mode to
redact_and_log first to confirm the redactor finds the right
spans without changing the prompt that goes upstream, then enable
inline once the audit trail looks correct.
The two modes
redact_in_transit rewrites the prompt to replace each PII span
with a placeholder token (<PII:EMAIL_0>, <PII:PHONE_1>,
<PII:NAME_2>), stashes the original spans server-side with a
60-second TTL, and re-injects the original spans into the streaming
response so the user sees their actual data in the model's reply.
The model never sees the PII; the user never sees the placeholders.
redact_and_log rewrites the prompt the same way but skips the
re-injection. The user sees the placeholders in the response. This
mode is for high-sensitivity workflows where the PII must not
round-trip even into the response stream.
The 60-second TTL
The span map lives for exactly 60 seconds. A redactor run that takes longer than 60 seconds loses the spans and the response surfaces the placeholder tokens instead of the original data. The 60s budget is generous for the typical model latency (single-digit seconds) but tight enough that a stalled response cannot leak spans into a future request's window.
The request id that keys the span map is server-generated and is never read from a client-controlled header, so an attacker cannot forge one to read another user's span map.
The latency-budget gate
The redactor wraps a transformer-backed entity recogniser, which has a warmed p99 latency around 256ms but can spike on long prompts. A per-request wall-clock budget (default 800ms) caps the redactor's time. On timeout, the redactor fails open (the request continues with the unredacted prompt) and writes an audit row carrying the entity count and types only (never the unredacted content).
The fail-open default is the safer of the two failure modes for an
org that depends on the gateway for chat latency. An org that
prefers fail-closed semantics can set the mode to off until the
latency stabilises.
On the roadmap
- A per-org fail-mode control so an org can opt into fail-closed semantics without turning the mode entirely off.
- A per-team override on the redaction mode so a team can be more aggressive than the org default without forcing every team to match.
- A live latency p95 plus p99 readout on the dashboard tile so an admin can spot a slow cold start before it triggers the budget gate.
Anomaly rate-limit
Status: Live today. The per-org anomaly rate-limit and its
anomaly_rate_threshold alert-rule are in force in production.
The anomaly detector emits one event for every detection. A misconfigured detector or a real spike can flood the store with thousands of events per minute, which both costs storage and drowns the alert-rule evaluator. The per-org rate-limit caps the emission rate.
The per-org cap
A per-org rate limit (default 10 per minute) caps how many anomaly
events the detector emits per minute, counted separately for each
anomaly type so one noisy heuristic cannot starve the others. The value
cannot be set below 1, so a misconfigured 0 cannot silence the detector
entirely.
When the cap is hit, the detector still writes the event but flips a
rate_limited flag to true so the dashboard can render a "Rate
limited" badge on the row. The row write is the audit evidence that the
detector fired; what the flag suppresses is the webhook notification, so
the audit trail stays complete without fanning every downstream
subscriber out on a runaway detector.
The alert-rule type
An anomaly_rate_threshold alert-rule fires when the count of
anomaly events in a rolling window exceeds a configured threshold.
The rule config carries two keys:
{
"window_hours": 1,
"threshold": 50
}
window_hours defaults to 1 and threshold defaults to 50. The
dashboard form constrains the config shape to exactly those two
keys; an attempt to inject any other key is rejected at the submit
handler.
The cooldown
Every alert-rule carries a cooldown that prevents the same rule from
firing twice in quick succession. The dashboard prefills a 15-minute
cooldown for the anomaly_rate_threshold rule type; a create that omits
the field entirely lands the 60-minute default the other rule types use.
The floor is enforced server-side, so even if the form submits a zero
cooldown the validator rejects it and a misconfigured rule cannot ladder.
On the roadmap
- A per-rule plus per-recipient cooldown so the same rule can fire immediately to the on-call SIEM but every 60 minutes to the Slack channel.
- An "anomaly digest" alert-rule type that batches the rate-limited rows into a single notification at the cooldown boundary so the alert recipient sees one rolled-up message instead of N rate-limited badges in the dashboard.
Access scoping
Status: Live today. Org-scoped enumeration, operator gating, and an owner/admin role gate on sensitive admin actions are all in force in production. The granular multi-permission catalogue described under "On the roadmap" below is not wired to any route yet.
Every admin surface enforces org-scoped enumeration. A small set of platform-operator surfaces (the cross-org and fleet-wide views) gate on an operator flag. Separately, an owner/admin role check already backs specific sensitive actions across most of the admin surface, including key reveal, billing, and member management. The granular multi-permission catalogue, which would name permissions individually per role instead of today's owner-or-not check, is on the roadmap.
Org-scoped enumeration
Every admin route resolves the caller's active org and masks the result set to that org. An admin with credentials for org A cannot enumerate, read, or mutate org B's keys, audit rows, billing, or settings; the query is scoped to the caller's org before it runs, so a cross-org probe returns the caller's own data or a 404, never another org's. This is the load-bearing tenancy boundary and it is enforced on every admin handler.
Operator gating
A small set of platform-operator surfaces (the cross-org and fleet-wide views) gate on an operator flag carried on the session. A non-operator session that scripts the endpoint directly is masked with a 404 before the handler runs, so the gate is enforced server-side rather than just hidden in the UI, and the route stays indistinguishable from one that does not exist.
Role assignments
Every member carries an org-scoped role of owner, admin, or
member, set on invite and changeable from the Settings → Members
pane by an owner or admin (a plain member sees the role read-only).
Promoting someone to owner is restricted to existing owners, and
the last remaining owner cannot be demoted or removed. Every invite,
role change, and removal writes an audit row. This role is a real
enforcement input today: it is what gates key reveal, billing, and
member management above, not a display-only label.
The Members pane also surfaces a separate, read-only "Roles" panel backed by the granular multi-permission catalogue on the roadmap below. That catalogue is not yet wired to any route guard, so the panel does not drive access; the role in the Members list above is the boundary the gateway actually enforces.
On the roadmap
- The granular multi-permission catalogue (named permissions such as
KEY_REVEAL,AUDIT_VERIFY, andBILLING_READ, mapped per role) wired to a uniform per-route guard, replacing the hand-rolled owner/admin check most admin routes carry today. - The read-only Roles panel wired to that catalogue's live enforcement state, once the guard above lands, instead of the separate table it reads from today.
Multi-region scaffolding
Status: Roadmap. The data-residency control surface records an org's
intended region today, but provider-pinned data-residency (routing an
eu org only to eu-region providers) is on the roadmap and not in
force yet.
The current build lands the data-residency control surface plus the read-side resolution so a later release can wire region-pinned providers without re-architecting. The region currently records the org's intended residency; provider pinning is on the roadmap.
The region values
An org's data-residency region is one of three values: us, eu,
or apac. The default is us, which keeps every existing org on
the US region until an admin sets the value via the Settings →
Security pane. A fourth value is rejected, so a typo cannot land a
rogue region.
Defaulting
The region resolution defaults to us whenever the stored value is
missing or empty, so the read path is safe to call across a deploy
window before every org has a region set.
On the roadmap
- Region-pinned routing so an
euorg only routes to providers whose region matches. - A per-team override on the region so a team in a US-default org can opt into EU residency without forcing every team to match.
- A region-aware webhook deliverer so a US-default org with a Frankfurt receiver routes the delivery through the EU egress pool rather than the US pool.
- A region-pinned audit-log composer so an evidence pack only carries rows from the region the auditor is scoped to.
PII customer-scoped enablement
Status: Roadmap. These controls are part of the gateway PII redactor, which is on the roadmap and not live at the request boundary today.
The redactor's latency budget, the deep-PII inspection (DPI) toggle, and the re-injection policy are per-org controls so an org can opt into a wider budget plus the DPI transformer plus a tighter re-injection policy without a process restart. The inline path reads the current values on every request, so a settings change lands on the very next request.
The three controls
- A per-org latency budget (default 800ms): the wall-clock bound the inline path hands the redactor.
- A per-org DPI opt-in (default off): enables the transformer-model recogniser for deeper detection.
- A per-org re-injection policy (default
always): controls how the response wrapper re-injects the original spans.
The latency budget override
An org that pegs the budget at 100ms gets fail-open behaviour on every prompt that exceeds 100ms; an org that widens to 3000ms gets the full transformer-model headroom. The dashboard clamps the input between 50ms and 3000ms to protect the operator UI from typos and runaway values. A submission outside the accepted range is rejected at the validator boundary.
The DPI lazy load
The DPI toggle gates the transformer-model recogniser. When on, the redactor loads the analyzer on the first request for the org and caches it for the lifetime of the process; the cold-start adds 200-500ms on the very first call but every subsequent request reads the cached analyzer.
The default (off) means an org that never opts in never pays the cold-start cost. A process that boots with zero DPI-enabled orgs never instantiates the transformer at all.
The re-injection policy
The re-injection policy takes one of three values: always,
trusted_only, or never. Any other value is rejected so a
misconfigured admin endpoint cannot land a rogue policy.
always is the default and matches the inline contract: the
response wrapper re-injects every per-request PII span so the user
sees their original data in the model's reply. trusted_only
re-injects only when the response originated from a trusted
endpoint; otherwise the placeholders stay in the response. never
skips the re-injection entirely so the response stream carries the
placeholders.
The Settings → Security pane exposes the three values and carries an inline caption naming the default-on contract plus the latency trade-off for the DPI toggle.
Anomaly detector extended heuristics
Status: Live today. The base heuristic, the five extended heuristics, and the per-type rate-limit windows are in force in production.
The anomaly detector fires one base heuristic
(thinking_budget_excess) plus emits one event per detection. The
detector is extended with five new heuristics covering request-rate
spikes, cost-rate spikes, failed-auth bursts, key-vault-reveal
bursts, plus webhook failure streaks. Each event carries a discrete
anomaly type so the dashboard can index-seek per type instead of
scanning a free-form reason field.
The five new types
The five new heuristics each emit an event tagged with a discrete anomaly type:
request_rate_spike: fires when the request count in a single minute exceeds 5x the 7-day per-minute p95 baseline. A 50-bucket sample floor holds the heuristic quiet until the baseline is meaningful, so a new or low-traffic team does not false-flag on its first burst.cost_rate_spike: fires when the per-org cost rate over a rolling 5-minute window exceeds 5x the 7-day p95 baseline.failed_auth_burst: fires when a single actor's failed-auth count over a rolling 1-minute window crosses 10 (a fixed threshold, no p95 baseline, because that many failures from one actor in one minute is anomalous regardless of the org).key_vault_reveal_burst: fires when a single actor's key-reveal count over a rolling 1-minute window crosses 5. The threshold is tighter thanfailed_auth_burstbecause a legitimate operator rarely reveals more than one or two keys in a minute.webhook_failure_streak: fires when a single webhook destination's delivery log shows 10 consecutive failures with no successes interleaved, walking back from the most recent delivery.
Per-type rate-limit windows
The per-org rate-limit is scoped to the firing anomaly type rather than
shared across every heuristic. The detector counts the events already
written for that org, that team, and that anomaly type inside the last
rolling minute, and compares the count against the org's cap; a detection
that would exhaust the type's own bucket flips the rate_limited flag on
the emitted event but writes the event anyway, so the audit trail stays
complete either way.
Per-type scoping is what keeps the budgets independent. Before it, a noisy webhook-failure-streak destination could starve the thinking-budget path, because all six heuristics drew on one shared bucket. Each type now gets the full per-minute cap to itself, so tuning the cap up for a high-traffic org does not trade one heuristic's visibility against another's.
Alert-rule integration
The anomaly_rate_threshold alert-rule counts every anomaly event the
org wrote inside the rolling window, without filtering by type, and fires
when the count exceeds the configured threshold. Its config is a closed
schema of exactly window_hours plus threshold; a third key, including
an anomaly_type filter, is rejected at the gateway boundary rather than
silently stored.
One heuristic does have its own rule type. auth_failure_burst_5m reads
failed_auth_burst events over a fixed five-minute window, which is the
shape a credential-stuffing spike actually has, so a login-loop or a
stuffing run can page separately from the org-wide anomaly count.
The 15-minute cooldown prefill carries forward on the
anomaly_rate_threshold rule type; auth_failure_burst_5m takes the
60-minute default unless the operator dials it down.
On the roadmap
- A per-detector exponential backoff so a heuristic that fires plus rate-limits in close succession backs off the bucket refill rate for the next window. The current buckets refill linearly; a malicious actor who learns the window can pace the attack to the cap.
- A per-heuristic alert digest that batches the rate-limited events into a single notification at the cooldown boundary.
- Full audit-chain coverage on the anomaly event records so the verifier no longer skips any rows.