What your security team can do to agents: per-call authorization, stop controls, containment. The capability, from the operator's side.
PLATFORM / SECURITY
A control plane in the execution path is a target.
GovernorAI sits where agents act, next to your credentials and your systems of record. That position is only defensible if the platform holding it is built to the standard it enforces. This page is the architecture, layer by layer, in enough detail to be argued with.
GovernorAI sits where agents act, next to your credentials and your systems of record. That position is only defensible if the platform holding it is built to the standard it enforces.
WHICH QUESTION THIS ANSWERS
Three security pages, three different readers.
Security appears in three places on this site, deliberately. This is the one for the architect reviewing the platform itself.
How GovernorAI is operated: data handling, deployment shapes, access control, incident response. What a security review is handed.
How GovernorAI is built: the defence-in-depth architecture of the gateway and control plane, and what happens at each layer when something fails.
ZERO TRUST, SPECIFICALLY
The perimeter is the action, and it is checked every time.
Zero trust is easy to claim and mostly means “we authenticate”. Four properties make it real here.
Authorization is not established at session start and carried. Every governed tool call is evaluated on its own, against the policy version in force at that moment.
per actionAn agent has its own identity, bound to a namespace, with its own credential path. It does not inherit the trust of whoever started it.
namespace boundA rogue identity fails closed at the gateway. A degraded one is constrained rather than trusted, and a paused agent is stopped before policy evaluation runs at all.
fail closedThe evaluation path is deterministic. Nothing probabilistic sits between a request and its verdict, so the same input resolves the same way every time.
deterministicDEFENCE IN DEPTH
Twelve layers, and what each one does when it fails.
Depth is only meaningful if a layer's failure mode is known. Each row states the mechanism, not the intention.
- OAuth2/OIDC against your identity provider, with SSO and SCIM provisioning.
- Multi-factor: TOTP and WebAuthn, not TOTP alone.
- Brute-force protection with account lockout and a progressive delay between attempts, not a fixed retry window.
- Credential freshness checks, email verification and a scoped password-reset path.
- JWT signing with dual-key rotation: new tokens sign with the current key while the previous key still validates, so a secret rotates without logging everyone out.
- CSRF protection and scoped cookies on the console path.
- Separate machine and agent credential paths, so an agent key is not a user session.
- Role-based access control against a permission registry, rather than role strings compared at the call site.
- Namespace binding on agent identity.
- Separation of duties on policy approval — the reviewer is not the author.
- Row-level scoping injected into the request context by middleware, then enforced at the database, so a missing filter in a query is not a cross-tenant read.
- Tenant-isolation tests sit beside the code they constrain — the audit chain, DLP and approvals each pin their own isolation behaviour.
- Every outbound call to a tenant-controlled URL goes through a shared SSRF-safe client whose authoritative check is a dial-time hook on the resolved IP — after DNS, not on the URL string. That is what defeats DNS rebinding; a URL blocklist does not.
- Refused: loopback, private, link-local including the cloud metadata address
169.254.169.254, CGNAT, unspecified, benchmark and multicast ranges, and their IPv4-mapped IPv6 forms. - The metadata address stays blocked even when private addresses are permitted for local development.
- Credentials encrypted with AES-256-GCM.
- In production the service refuses to start without a persistent encryption key rather than falling back to an ephemeral one — a fail-closed startup guard, not a warning.
- Pluggable secret providers, including AWS Secrets Manager and Vault.
- A certificate manager with a rotation window, so expiry is a scheduled event.
- Distributed rate limiting with atomic Redis operations, so concurrent requests cannot race past the limit.
- An explicit fail-mode for when the limiter backend is unavailable.
- A specific defence against memory amplification in the limiter itself — the rate limiter is not a memory-exhaustion vector.
- Call arguments are recorded as SHA-256 digests, never raw values. The record proves what was attempted without becoming a second copy of the data.
- DLP classification with its own tenant-isolation guarantees.
- No prompts, no completions, no customer PII in governance logs.
- Fail-closed is enumerated case by case in the gateway, not asserted once: a rogue identity fails closed, a paused agent fails closed before policy evaluation, and a shaping operation that cannot be proven to have landed fails closed rather than passing through unshaped.
- Any transport error, timeout, non-2xx or unparseable response resolves to deny.
- Audit entries are hash-chained with SHA-256 — each carries
prev_hashandentry_hashwith a sequence, so a removed or edited entry does not verify. - The chain cursor is re-seeded from storage on restart, so a restart continues the existing chain instead of silently beginning a new one.
- Chain behaviour is pinned under tenant binding and under high availability, not only on a single node.
- Kill switches at four target scopes —
agent,tool,namespaceandsession— plus account-wide and global switches, which are a separate flag rather than a fifth scope. Containment does not mean stopping the estate. - Activation writes to the registry and fires a webhook, and propagates over pub/sub.
- The same activation path is what the shadow-AI quarantine flow reuses, so discovery findings and manual containment share one mechanism.
govulncheckon the dependency graph andgosecproducing a SARIF inventory, on push and on a schedule.gitleaksacross the commit range, failing on any finding.- A production security baseline gate that rejects an untracked or uncommitted security decision — the release cannot proceed on an undocumented exception.
STATED PRECISELY
Transport, and two corrections.
Every TLS configuration in the platform, and the CDN policy in front of it, sets a 1.2 minimum. That is a strong modern posture. It is not the same claim as “TLS 1.3”, and this page does not make the stronger one.
Two statements carried by earlier marketing material are not supported by the platform as built, and are corrected rather than repeated here.
“TLS 1.3 in transit” overstates it. TLS 1.3 is negotiated when the client offers it, but the enforced floor is 1.2 in every configuration, including the CDN. Confirmed: there is no other termination point with a stricter policy. Every tls.Config in non-test code sets MinVersion: tls.VersionTLS12 — the Redis client, the auth state store, the Kubernetes token-request client, the certificate manager and the external policy-engine transport — and no configuration anywhere sets VersionTLS13 as a floor. The CDN pins minimum_protocol_version = "TLSv1.2_2021" to the viewer and origin_ssl_protocols = ["TLSv1.2"] to the origin. The ingress manifests carry no SSL-policy annotation at all, so the load balancer in front of them keeps its provider default rather than a stricter one.
“mTLS between all internal components” overstates it. Mutual TLS is implemented as an opt-in client-certificate configuration for the external policy-engine connection, which correctly refuses to start with a certificate but no key. It is not a blanket property of internal traffic. No service-mesh layer makes a scoped version of it true either: the repository contains no Istio or Linkerd manifests, no PeerAuthentication resource, and the only Envoy configuration present — the gateway-insertion ext_proc filter — declares no client-certificate validation context. RequireAndVerifyClientCert appears exactly once in the codebase, in a test.