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.

Verified per action, not per session Fail-closed enumerated, not asserted No credential path through us
DEFENCE IN DEPTH, FROM THE OUTSIDE IN Transport TLS on every hop Identity Verified per action, not per session Authorization Org-scoped, row-level isolation in the database Policy evaluation Deterministic. No model in the decision loop Execution Fail closed — no decision means no action Evidence Hash-chained, written after the decision Each layer states what it does when it fails, not that it will not.

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.

verified per actionfail closedno credential path

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.

Security & AI Security

What your security team can do to agents: per-call authorization, stop controls, containment. The capability, from the operator's side.

Trust & security

How GovernorAI is operated: data handling, deployment shapes, access control, incident response. What a security review is handed.

This page

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.

Verification is per call

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 action
Agent identity is not user identity

An 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 bound
An unknown identity is denied

A 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 closed
No model in the decision

The evaluation path is deterministic. Nothing probabilistic sits between a request and its verdict, so the same input resolves the same way every time.

deterministic

DEFENCE 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.

 
Layer
Mechanism
01
IdentityWho is asking
  • 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.
02
SessionWhat a token is worth
  • 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.
03
AuthorizationWhat that identity may do
  • 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.
04
TenancyWhat it may ever see
  • 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.
05
OutboundWhat the platform may reach
  • 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.
06
SecretsWhat is held, and how
  • 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.
07
AbuseCost of being noisy
  • 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.
08
DataWhat is written down
  • 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.
09
EnforcementWhen something goes wrong
  • 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.
10
RecordWhether the evidence holds
  • Audit entries are hash-chained with SHA-256 — each carries prev_hash and entry_hash with 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.
11
ContainmentStopping it
  • Kill switches at four target scopes — agent, tool, namespace and session — 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.
12
BuildBefore it ships
  • govulncheck on the dependency graph and gosec producing a SARIF inventory, on push and on a schedule.
  • gitleaks across 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.

Stated precisely Transport is TLS 1.2 as a negotiated floor, with TLS 1.3 used wherever both ends support it.

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.

Honesty note

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.

Continue