Skip to main content

Security Zones

Zones classify targets — the MCP servers an agent can reach — so that crossing a perimeter becomes something you can scope, escalate on, and reconstruct afterwards.

The problem they solve is the one workflow that touches three vendors and leaves no story behind it. A session that reads customer records and then posts externally is both an ordinary support workflow and the exact shape of exfiltration. Zones make the difference legible.

Zones classify targets, not tools

There is no tool-level metadata table to hang a zone on, so v1 resolves at server granularity. Finer grain is a later sprint, not a missing piece of this one.

The shipped zones

Five ship by default, and the set is tenant-extensible:

ZoneTypical contents
publicDocumentation, public APIs, search
internalOrdinary internal systems
pii_sensitiveCustomer records, HR, anything personal
infrastructureDeployment, cloud control planes, CI
external_writeEmail, ticketing, anything that emits outside the org

Inference proposes, an admin promotes

This is the precision rule expressed as schema rather than as a feature flag — and it is why zones need no opt-in switch.

Every target lands at zone_state = 'inferred', assigned by name-and-URL heuristics at registration. An inferred zone is record-only by construction. It emits ZONE_SUGGESTED and allows the call, no matter how alarming the inference looks.

Only an admin promoting a target to confirmed makes it deny inline.

The enforceable state is not reachable by accident

An imprecise detector records and lets an admin follow up. A deterministic one — an admin's own classification — may deny. A deployment that classifies nothing behaves exactly as it did before zones existed.

Cross-zone reach folds into blast radius

Cross-zone reach is a blast-radius question — how far can this one call travel — so zone rules became a single new branch inside the existing blast-radius check rather than a sixteenth sequential gate in the hot path.

The zone logic is pure and synchronous, with no database, agent, or session access: the engine resolves a decision from rows it already holds and passes that decision in. Omitting it reproduces the prior behaviour exactly.

The exfiltration shape

A sensitive cross-zone transition inside a single session — pii_sensitive followed by external_write — runs the zone_transitions policy and emits a ZONE_TRANSITION event carrying the session's full zone path. The crossing is reconstructable from the record, not merely alerted on at the moment it happened.

Transitions are judged against every zone the session has touched

Not just the immediately preceding one. Otherwise reading customer records, then a public docs page, then posting externally would launder the crossing.

Seeded to escalate, not to deny

"Read customer records, then send an email" is both the exfiltration signature and a support workflow that runs a hundred times a day. Denying it outright breaks real work, and a control that breaks real work gets switched off.

So the seeded pairs escalate: a human is put on the one decision that matters, and the transition is recorded either way.

Direction matters, and the pairs are ordered. publicpii_sensitive is ordinary. pii_sensitivepublic is not.

The session zone path is durable

The path lives on the session record (sessions.zones_touched), not in process memory. The path is the evidence — an in-memory set would work on one box and fail silently across a fleet.

It advances only on permitted calls. A denied call never reached the zone, and recording it would corrupt the path that every later transition is judged against.

Scoping an agent to zones

allowed_zones on the agent record, and in the agent JWT.

NULL means "not scoped", not "nothing allowed"

A NULL value reads as the default internal grant. That is what lets a newly-created agent be scoped without anyone writing a value — see one-line onboarding.

Where zones meet autonomy

The infrastructure zone requires autonomy level A2 or above, and that requirement is enforced only when the tenant has enabled autonomy enforcement. Zones inherit that opt-in rather than introducing a second switch.

Zone breadth and sensitivity also feed the BRF Access dimension. Holding pii_sensitive and external_write together scores above the sum of its parts, because that combination is the lethal-trifecta shape.

API

EndpointPurpose
GET /api/v1/policy/zonesList zones for the tenant
GET / PUT /api/v1/targets/{id}/zoneRead or set a target's zone and state
GET / PUT /api/v1/agents/{id}/zonesRead or set an agent's allowed_zones
GET / PUT /api/v1/policy/zone-transitionsThe transition policy

The dashboard ships a zone grant editor and a zone-path renderer on the session view.

Upgrading

Nothing enforces on upgrade. Every target arrives inferred, which records and prompts but never blocks. The first denial requires an admin to have looked at a target and confirmed its zone.

There is a schema change on both planes, so a data-plane upgrade runs alembic upgrade dp@head and a control-plane upgrade runs alembic upgrade cp@head.