Security model
What is authenticated, what is loopback-only, what lives in memory, and the limits to know before you deploy.
AgentShield is pre-1.0 and built for evaluation and development. This page states what it protects, what it does not, and how to run it safely.
The HTTP API has no authentication
Every route served on --listen (graph, findings, OTLP receiver, Firehose receiver, UI, and remediation) is unauthenticated and has no authorization. Anyone who can reach the port can:
- read the full graph, including resource names, labels, relationships, and evidence IDs;
- read findings;
- send telemetry that the registered mappers accept;
- if live remediation is enabled, prepare and approve remediations;
- if rule review is enabled, approve or reject Deployment rule drafts and request new ones, which calls the configured model.
Defaults that limit this:
--listendefaults to127.0.0.1:8088.- Live remediation is registered only when discovery is running and the listener is a loopback address (
127.0.0.0/8,::1, orlocalhost). On any other address, the remediation endpoints return503and the process logslive remediation API disabled on non-loopback listener. - The rule review and regenerate routes act only on a loopback listener, or when
--rule-review-apiis set. On any other address they return503. - The Firehose receiver exists only when
--aws-firehose-stream-arnis set, and checks the stream ARN, access key, protocol version, and request ID on every request.
If you bind to a non-loopback address, put AgentShield behind infrastructure that authenticates and authorizes every request (for example an authenticating reverse proxy, a service mesh with mTLS and authorization policy, or a private network with strict access control). The UI sends no credentials of its own and expects same-origin requests.
Browser requests
Two checks stop a website open in your browser from using a loopback AgentShield on your behalf:
- JSON content type. Every
POSTroute (remediation prepare and approve, rule review and regenerate, the OTLP receiver, and the Firehose receiver) rejects requests that are notapplication/json; OTLP also acceptsapplication/x-protobuf. A page on another origin cannot send those types without a CORS preflight, and AgentShield never answers a preflight with permission, so the browser refuses to send the request. - Host check. On a loopback listener the server rejects any request whose
Hostheader is notlocalhostor a loopback IP. This blocks DNS rebinding, where a hostile page points its own domain name at127.0.0.1to become same-origin and get around the content-type check. The Firehose route is mounted in front of this check; it relies on its access key instead.
These are not authentication and not a complete CSRF policy. They do not stop:
- any process or user on the same machine (or, in a Pod, in the same network namespace) that calls the API directly, for example with
curl; - anyone who can reach a non-loopback listener (the Host check is off there, though remediation is disabled);
- a cross-site
GET. A page can trigger one but cannot read the response. TheGET /api/v1/manifestandGET /api/v1/overviewroutes record a manifest row as a side effect; repeated requests return the same row.
Remediation is gated by people, not by policy
- Reasoning, detection, discovery, and graph publication never execute a remediation.
- Execution requires a separate approval request that names a plan prepared in the same process. The browser cannot submit its own proposal or provider payload.
- Prepared actions are in memory. There is no durable approval record and no user identity. Any local process or local user that can open a connection to the loopback listener can prepare and approve an action; see Browser requests for what stops other websites.
- Verification proves that a declared policy exists, not that it is enforced.
- The Kubernetes credentials of the process determine what it can change. Grant read-only RBAC unless you need remediation. Locally,
make runuses your current kubectl context, so an approved remediation can do anything you can; use a read-only context or--kubernetes-kubeconfigif you only want to look.
See Remediation.
Telemetry and evidence are sensitive
- Telemetry properties, evidence, and raw sink contents can reveal internal topology, request paths, and addresses. Treat the JSONL file and ClickHouse tables as sensitive data.
- Mappers must not put credentials, tokens, authorization headers, request bodies, or principal names into normalized properties. The agentgateway normalizer, for example, records only that a request was authenticated.
- The OTLP receiver never logs record content; rejection responses contain only counts.
- Plugin and source IDs on telemetry come from mapper registration, never from the payload. But anyone who can send records that match a mapper can inject plausible telemetry. Restrict who can write to your collector and to AgentShield.
- Both HTTP receivers acknowledge before the raw sink write. The OTLP receiver returns
200and the Firehose receiver returns success as soon as the events are in the in-memory queue (up to 100,000 events). Events still queued are lost if the process crashes, or if it is stopped and the 10-second shutdown drain runs out. The sender does not retry them, because it already got a success. See Telemetry failure behavior.
Reasoning MCP server
agentshield-reasoning-mcp serves packet-backed graph and telemetry tools over
streamable HTTP at /mcp. Its default listener is 127.0.0.1:8090; the saved
packet and optional telemetry context can contain sensitive graph data. The
server has no authentication or authorization. Keep it on loopback or put it
behind infrastructure that authenticates and authorizes every request before
binding to a non-loopback address.
Provider data
- Kubernetes Secrets: only metadata and a sorted list of key names are stored. Values, type, and annotations never reach collections, PostgreSQL, or the graph. The informer still reads Secrets into memory, so the service account needs read access to them.
- The AWS plugin uses the default SDK credential chain and never logs credentials.
- Native events in PostgreSQL contain provider object JSON (minus Secret values). That includes ConfigMap
dataand literal Podenvvalues, which are common places for credentials to end up. Protect the database accordingly.
Model endpoints
AgentShield calls the model endpoint only for the features you enable. With --agentic-investigation, it sends graph data: resource IDs, kinds, network/role, security semantics, relationships, facets, evidence IDs, and tool results the model requests. With --deployment-rule-authoring, it sends, for each Deployment Pod template revision, the Deployment’s name, namespace, and service account, plus a summary of its observed outbound requests: destination names and roles, request methods and paths (query strings removed; numeric, UUID, and long hex path segments replaced with {id}), outcomes, and counts. Paths can still contain other identifiers, such as names or emails. Setting --model-endpoint alone sends nothing. Running detection rules never calls a model. Prompts treat these values as untrusted data. Use a model endpoint approved for this data, keep API keys in environment variables, and note that requests use store=false with the Responses API.
Content Security Policy
The UI and API send Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none', plus Referrer-Policy: no-referrer and X-Content-Type-Options: nosniff. UI changes must not add inline scripts or styles, or load assets from other origins.
Database safety
- Integration tests truncate the database they are given. Never set
AGENTSHIELD_TEST_DATABASE_URLto a database you want to keep. --database-urlexposes the password in the process list; useAGENTSHIELD_DATABASE_URL.
Out of scope today
Tenant isolation, per-source authorization of telemetry producers, audit logging, rate limiting, and secret-scrubbing of provider payloads beyond Kubernetes Secrets.