TL;DR

Google's open-source Agent Mesh, published under the google GitHub organization as google/sam and since renamed google/agentmesh, is a private network in which a node sits beside an AI agent, publishes its MCP tools and models, and calls other nodes' services. Two critical defects let a remote attacker run tools on every MCP backend in the mesh. In alpha.1 and alpha.2 the /libp2p-http ingress forwarded requests to backend service handlers, command-and-stdio MCP servers included, without the Biscuit token or mesh-enrollment check the MCP path enforces (CVE-2026-102503, fixed 0.1.0-alpha.3, released 2026-08-06). Through alpha.8, GET /info disclosed the OIDC configuration without authentication, POST /register auto-enrolled any valid token from the configured OIDC provider with no approval or claim filter, and the shipped default policy bound sam:system:authenticated to wildcard services and targets, so any holder of an identity-provider token obtained a 90-day mesh credential with read, write and execute access on every backend (CVE-2026-103091, fixed 0.1.0-alpha.9, released 2026-09-07). A third vendor advisory in the same batch, with no CVE, let an anonymous caller fetch an approved router's Biscuit from GET /enroll/status and use it as a bearer credential (GHSA-hp3x-79wr-rx66, high, fixed alpha.9). Google published the two CVE records on 2026-10-19 with CVSS 4.0 9.3; the vendor pages from 2026-09-04 and 09-06 carry CVSS 3.1 9.8. The project says it is "not an officially supported Google product" and is pre-1.0; the current release is v0.1.1 (2026-10-18). Any mesh still on an alpha below alpha.9 is open.

What happened

What the product is. The repository README describes a private network for AI agents: a node runs beside an agent to publish tools and models, find and call other nodes' services, and provide a verifiable identity; nodes connect directly or through relays; each node exposes a local MCP server and an OpenAI-compatible API. The repository is tagged mcp, a2a and a2a-protocol, is Apache-2.0, had 1.1k stars and 184 forks on 2026-10-19, and the README disclaims official Google support. The vendor advisories and the Go module path call it SAM (Sovereign Agent Mesh); the CNA records say "Google OSS Agent Mesh (SAM)"; the repository now redirects from google/sam to google/agentmesh. Both names are in this file so either search finds it.

CVE-2026-102503, the unauthenticated ingress (GHSA-r6hp-67wp-c7jx, published 2026-09-04, reporter Yanchon918s). A node exposes backend services over two libp2p paths. The MCP stream handler is wrapped in the Biscuit authorization middleware; StartIngressServer in cmd/sam-node/node.go registered no equivalent check and forwarded /libp2p-http requests straight to the service handler. The connection gater checked only a ban list, not enrollment, and no private-network pre-shared key was configured, while the shipped defaults bind libp2p to 0.0.0.0 and discover peers through the public testnet DHT, so an affected node was reachable. The reporter's lab test showed an un-enrolled peer receiving HTTP 200 and a backend execution for a tool the policy denied over the ingress, while the same call over the MCP path was rejected. For command-backed MCP services the request reaches the backend subprocess, which the advisory rates as RCE-capable with a scope-changed ceiling of 10.0; for URL-backed services the node becomes an unauthenticated proxy to internal addresses. Fix commit 433bc99 (2026-06-30) applies the same Biscuit verification to every ingress request and strips and re-stamps identity headers before proxying; the alpha.3 release notes (2026-08-06) carry "Fix security gap in HTTP Datapath ingress and proxy token leak." The CNA range is 0.1.0-alpha.1 through alpha.2; there is no workaround.

CVE-2026-103091, open enrollment on an allow-all default (GHSA-cgmg-9xf6-rrgw, published 2026-09-06, reporter Eli Ainhorn of Noma Security). Five findings combine. The MCP proxy (HandleStreamPassThrough in mcp_service.go) applied no authorization, so any mesh member could invoke any tool on any node. GET /info returned the OIDC issuer, client id, audience and router addresses to anyone. POST /register auto-enrolled any valid JWT from the configured provider with no approval, invitation or claim filtering, so, in the reporter's words quoted by the vendor page, "any valid token from the configured provider works." The default policy bound sam:system:authenticated to wildcard services and targets, which made the Biscuit check pass for every member. Bans were keyed on peer_id, which an attacker regenerates with a new local keypair, and HandleRegister had no ban check. A one-hour OIDC token yielded a 90-day mesh credential. The CNA description says the attacker "can obtain a mesh credential with full read, write, and execution access on backend services," and the fix in alpha.9 "enforces a fail-closed default policy" (the record's sentence is cut at that point in the API response read this sweep). Range alpha.1 through alpha.8; the alpha.9 release note (2026-09-07) reads "3 security fixes and advisory published."

GHSA-hp3x-79wr-rx66, the anonymous Biscuit fetch (published 2026-09-06, reporter makino-yuto, high, no CVE). GET /enroll/status took only a peer_id query parameter and never read the Authorization header; for an approved bootstrap enrollment it returned the peer's signed Biscuit, and the same control plane accepted that token on /policies and /routers/lease. The peer id is published by the unauthenticated /info route. The reporter replaced a router's advertised addresses with the stolen token. The stolen token stays valid for its TTL (24 hours by default) and the endpoint keeps returning it while the enrollment row persists; routers enrolled through the bootstrap-token path, the default router configuration, are the realistic victims, and the endpoint is on the gateway's public allow-list. The reporter noted that PR #324, which addressed a separate audit, still disclosed the Biscuit when rebuilt; the vendor page lists alpha.9 as the patched version. This file records that note and does not independently verify the alpha.9 behaviour.

Dates and scores, kept separate. Vendor advisories: 2026-09-04 and 2026-09-06, CVSS 3.1 9.8 on both CVE-bearing pages. Fix releases: alpha.3 on 2026-08-06 (the ingress fix commit is 2026-06-30, five weeks before the release that shipped it) and alpha.9 on 2026-09-07. CVE records: published 2026-10-19 by the Google CNA, CVSS 4.0 9.3 (AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H), no ADP score at read time. The GitHub Advisory Database rows for the two CVEs are unreviewed and show no package or version, so a scanner keyed on the database will not flag a go.mod pin; the vendor pages carry the github.com/google/sam Go module with the ranges. This file is dated by the vendor's first advisory; the database rows that surfaced it are six weeks younger.

Why it matters here. Agent Mesh is an MCP and A2A fabric: the point of the product is that one agent's tools are callable by another's. Both defects turn "callable by enrolled peers under policy" into "callable by anyone who can dial the node," and the second one does it with the identity provider's own tokens, so a company whose OIDC provider issues tokens to every employee had every employee, and anyone holding a leaked token, as a mesh administrator. The pattern is the one in Omnigent's header trust and Archon's unarmed API gate: the agent control plane ships with the gate open or trusting, and the fix is a default change.

Two-source note. The vendor advisories and the Google CNA records are the primary for the mechanism and ranges; the three reporters are independent of each other; the release pages give the fix dates. No outlet had covered the advisories when this file was written.

Am I affected?

# Module pin in any Go project that embeds a node
grep -rn 'github.com/google/sam\|github.com/google/agentmesh' go.mod go.sum 2>/dev/null
# A running node: version string and the listening ingress
sam-node --version 2>/dev/null; agentmesh --version 2>/dev/null
ss -ltnp 2>/dev/null | grep -i 'sam-node\|agentmesh'
  • Any 0.1.0-alpha.1 or alpha.2 node that was reachable on its libp2p port is in scope for CVE-2026-102503, with no workaround.
  • Any node or control plane below alpha.9 with an OIDC provider configured is in scope for CVE-2026-103091; the check is whether GET /info on the control plane answers without credentials.
  • Any control plane below alpha.9 with routers enrolled through bootstrap tokens is in scope for the Biscuit disclosure.
  • The alpha line is reachable through the project's public testnet DHT by default, so "internal only" is not an exemption unless the bind address and discovery were changed.

If you are affected

  1. Upgrade to v0.1.1 (2026-10-18) or at least 0.1.0-alpha.9; alpha.3 closes only the ingress defect.
  2. Treat every backend a node published as having been callable by unauthenticated peers: rotate the credentials those MCP servers, A2A agents and inference endpoints hold, and read their logs for calls from unenrolled peers. If an MCP server was malicious covers the per-tool review.
  3. Revoke and re-issue mesh credentials and router leases minted before the upgrade; a Biscuit obtained from /enroll/status stays valid for its TTL and a 90-day enrollment credential outlives the fix.
  4. Review the policy file: after alpha.9 the default is fail-closed, and an explicit wildcard binding for sam:system:authenticated carried over from an alpha configuration recreates the defect.

Prevention

  • An agent fabric's enrollment endpoint is an authentication boundary; require an approval step or a claim filter on top of "valid token from our provider." See agent sandboxing and MCP hygiene.
  • Pre-1.0 agent infrastructure from a large vendor's GitHub organization is still pre-1.0; read the README disclaimer and the security tab before putting production tools behind it.
  • Run the advisory-database query for the product name each month: these records sat on the vendor tab for six weeks before a CVE made them searchable.

Sources