In my previous post I looked at AWS AgentCore Gateway, which checks each tool call against a Cedar policy, and argued that it needs something beside it that remembers the session. Google announced its own Agent Gateway at Gemini at Work 2026. I expected the same kind of per-request firewall, but the docs surprised me: Google's gateway does look at history, by handing it to a language model.

Below I go through what Google's stack checks, run one multi-agent attack through it, and look at where my two open-source projects, SwarmSentinel (tool path) and SwarmSheriff (model path), would fit. What I say about Google's product comes from its public docs as of October 2026. Several of the pieces are in Preview, so details may change. The integration I describe at the end is a design, not something I've built.

What Google's gateway checks

Agent Gateway is the network entry and exit point for agent traffic: user to agent, agent to tool, agent to agent. It passes through HTTP traffic, including MCP and A2A, and for MCP it parses the request so policies can match on attributes such as the tool name. Around it sit several layers, and they work in quite different ways.

The base layer is identity. Each agent gets a SPIFFE ID, and mTLS and DPoP are enforced. Outbound calls are denied unless an IAM policy grants the agent access to the destination and the destination is registered in Agent Registry. IAP enforces this, and IAM conditions can see MCP attributes like mcp.toolName and whether a tool is read-only. All of this is deterministic and default-deny, and I think it's the strongest part of the design.

Model Armor adds content filters that scan prompts and tool responses for prompt injection and sensitive data. Like any classifier, it has to recognise the attack in the text.

Semantic Governance Policies are the new idea. Administrators write natural-language constraints. When the model proposes a tool call, the gateway sends the proposal, the constraints, the tools manifest and the chat history to a policy engine. It checks two things: whether the call matches the user's intent, and whether it complies with the constraints. A denied call is removed from the model's response before the agent sees it. The docs are frank that the engine "uses an LLM to implement natural language policies" and that "verdicts may not be accurate". They also say it isn't a substitute for IAM, rate limits or network controls. The feature is in Preview.

Finally, every policy type is enforced through authorization extensions managed with Service Extensions, and you can delegate decisions to your own engine the same way. I come back to that hook at the end.

Semantic Governance can catch things a rule engine can't express, and I don't want to undersell that. An agent can do something no rule forbids that the user never asked for: emailing the whole customer list when asked to fix one record, for example. A model reading the conversation may notice. SwarmSentinel won't, because the provenance of every input is clean.

The invoice relay, run through Google's layers

Here is the scenario I used last time, from SwarmSentinel's synthetic suite. An orchestrator hands invoice processing to a parser agent. The parser reads a vendor invoice that contains instructions to move money. The parser has no payment rights, so it messages the ledger agent, which does, and asks it to "settle the invoice as instructed".

Take each layer in turn as the ledger agent proposes payments.transfer.

IAP and the registry allow it, because the ledger agent is registered and holds the role for the payments tool. That's correct, since it does.

Model Armor gets a real chance when the parser reads the invoice, because it scans tool responses. If the injected text looks like an injection, it's flagged there. A paraphrased instruction, one split across two documents or one that reads like ordinary vendor boilerplate may get through. The message the ledger agent receives contains no malicious text at all.

Semantic Governance is the interesting one. It checks whether the transfer matches the user's intent. For the ledger agent, the "user" in that conversation is the parser agent, and the parser's request is the transfer. As far as I can see, the call matches the intent of whoever asked. This is what bothers me about judging intent in a multi-agent system: the upstream agent's intent is the thing the attacker took over. The docs don't say whether chat history spans more than one agent. If it only covers the ledger agent's own conversation, the poisoned invoice never appears in what the judge reads. If it does reach back to the original document, the judge is now reading attacker-written text while deciding, which is the same position the compromised agent was in.

I'm not claiming the judge would fail. A good constraint ("transfers must match an approved purchase order") could catch this case, and an LLM might notice that something is off. Still, the decision depends on a model's reading of text, and the attacker wrote some of that text.

What deterministic session state adds

SwarmSentinel implements ASP (Agent Security Policy), a policy model I proposed in a preprint. It's a proposal, not a standard. It handles the invoice relay without reading any of the text. The parser read content marked untrusted, so its context is tainted. The taint follows the message to the ledger agent, and the policy withdraws payment capability from tainted contexts. The transfer is dropped, and the flight recorder logs the rule that fired and the event where the taint started. How the invoice was worded makes no difference, because no step in that decision reads the wording.

This is the main difference from Semantic Governance. The decision rests on where content came from, and the attacker has no way to argue with provenance. The other ASP controls work the same way:

  • Admission and lineage: a spawned agent's scope has to sit inside its parent's, at runtime, with a depth cap. Agent Registry says which agents may exist. Lineage says what a particular child may do, given who spawned it.
  • Write caps per shared resource and step budgets per agent, which the Semantic Governance docs explicitly leave to other controls.
  • Repeated-intent throttling that counts distinct agent IDs, for an attack that retries through fresh identities.
  • Graph tripwires (injection spreading to several agents, delegation loops, coordinated writes) that revoke an agent and everything it spawned.
  • A report-only mode for asking "what would this policy have done?" I've used it to replay records from the AI Village dataset (AI Digest, "AI Village dataset", 2026). Those runs are counterfactual: they show what the policy would have flagged, not anything it stopped.

You pay for this with coarseness. Taint blocks some legitimate actions, because it doesn't try to tell a harmless request from a malicious one. An LLM judge makes the opposite trade, which is why I'd run both.

The model path: Model Armor and SwarmSheriff

Google's gateway sits between the agent and its model as well as its tools, so Model Armor can screen outbound prompts for sensitive data. SwarmSheriff covers the same exit for agents that don't run on Google Cloud, such as coding agents on a laptop calling Anthropic or OpenAI. It's a single Go binary acting as a loopback proxy. It classifies each request against data classes the company defines, checking source labels and fingerprints of known documents before patterns and keywords, and calls a classifier only for what's left ambiguous. Report mode is the default, and it never stores request bodies.

The part I think is different is the link to SwarmSentinel, which is built and tested. An ASP policy can label a context when a tool call touches something sensitive, for example any argument pointing at ~/.aws or any call to the CRM. When that agent next calls its model, SwarmSheriff resolves the agent's engine-issued credential and gets its labels. A data class can then hold the request whatever the prompt says. Revoked agents can't reach their model either. A content scanner, Model Armor included, has to find the secret in the prompt. A label says this agent touched the secret, so the prompt is held even if the agent has paraphrased or encoded it.

Google Agent Gateway layers SwarmSentinel SwarmSheriff
Decides by IAM rules, classifiers, an LLM judge Provenance, lineage and counters Labels, fingerprints, patterns
Memory Chat history (Semantic Governance) Session graph across all agents Labels from SwarmSentinel
Deterministic IAM yes; Model Armor and Semantic Governance no Yes Yes for the first three steps
Where it runs Google Cloud, managed Anywhere; Python engine Anywhere; loopback
Maturity Product, parts in Preview Research prototype Research prototype

How I'd connect them

Agent Gateway lets you add a custom authorization engine as a Service Extension, bound with an authorization policy. In Google's codelab, IAP is attached with the REQUEST_AUTHZ profile, which runs once per request at the headers stage, and Model Armor with CONTENT_AUTHZ, which streams body events. A SwarmSentinel extension would need the body to see tool arguments, so it would most likely use the content profile, or rely on the gateway's parsed MCP attributes if those reach custom engines.

The shape would follow the codelab's bindings:

# Sketch only. Field values follow the codelab; check the Service Extensions # reference for how a self-hosted backend is referenced and what it receives. name: swarmsentinel-authz service: <your SwarmSentinel extension backend> failOpen: false timeout: 1s 
{ "policyProfile": "CONTENT_AUTHZ", "action": "CUSTOM" } 

The extension would turn each MCP call into a proposed action for SwarmSentinel's evaluate endpoint. The agent ID would come from the SPIFFE identity, the target from the MCP tool name, and a span ID from the request. A denial would be returned as the gateway's deny. The codelab sets failOpen: true on its extensions, which is fine for a demo, but I'd want a security control to fail closed. SwarmSentinel would also have to speak the extension protocol, while today it's a REST service. I haven't verified the callout contract, so treat this as the shape of the work, not a recipe.

The order of extensions matters as well. You'd want SwarmSentinel to see calls that IAP denies, because repeated probing counts toward its budgets. Whether a custom engine sees a request that an earlier policy has already denied is something I'd test first.

Limits

SwarmSentinel and SwarmSheriff only see traffic routed through them, and SwarmSentinel is a code boundary in one process, not a tamper-proof control. Google's gateway enforces at the network edge with attested identities, which my prototypes can't match. Model Armor's classifiers are far better at spotting injected text than my regex detectors. And SwarmSheriff's evaluation set is still too small to quote accuracy numbers.

I like a lot of Google's design, especially default-deny connectivity and identity on every hop, and I appreciate that the docs say plainly the LLM judge is probabilistic. My concern is narrower. In a swarm, the intent behind a tool call usually comes from another agent, and that agent may already be compromised. Tracking provenance and lineage gives you a reason to refuse that holds however the request is worded, and an LLM judge can't provide that.

Both repos are MIT licensed. If you're on Google Cloud and want to try the extension route, I'd like to hear the feedback.