You already know MCP (Model Context Protocol, the open standard a chat app uses to call a tool outside the chat) as a token bill. The token-cost piece is that menu. This week the same pipe showed up as a trust bug, now called MCP protocol pivoting. An agent (a program that asks a model what to do next, then runs the tool the model names) read someone else’s sentence and treated it as an order. The tool then fetched a web address that sentence chose.

Google, JPMorgan Chase, Weaviate, France’s digital directorate, and the city of Tangerang each fixed a version of that mistake. Five United States federal servers were still in triage in the 6 October write-ups. The useful part is not the logo list. It is the check at the bottom, which you can run on a server you actually installed.
What an agent is, before any protocol

An agent is a loop, not a mind.
You type a goal. A model (a system that continues text; a large language model is the kind people mean by an AI chat) writes the next step as more text. If that step names a tool (a function the program is allowed to run, such as fetch this URL or query this database), your code runs the function and pastes the result back into the conversation. The model writes again. There is no separate memory. The next call only knows the text in front of it.

That loop is the whole agent. Anything the model can convince the loop to put in a tool field, the tool will try to do. The model is not a security check. It is the thing that fills in the field.
What MCP is, in one connection
MCP is the plug between that loop and the tool.
The project docs compare it to a USB-C port for AI apps: one shape, many devices. Three roles sit on it. The host (the app you talk to, such as Claude, Cursor, or a chat your team built) holds the conversation. The client (the small connector inside that host) speaks MCP to one server. The server (a separate process you installed) is what actually exposes the tools, and it is usually where the API key sits. The model does not hold the key. The server does.

That is why a sloppy tool is worse than a sloppy sentence. The sentence borrows the server’s key and the server’s place on the network. A tool result (the text that comes back, such as a page, a row, or an error) is also just text. The token-cost piece treats a huge result as a bill. This piece treats it as writable by someone who is not you.
The server is the part that touches the network. A firewall can stop a stranger at the door. It cannot stop this server, because the server is already inside. The drawing of that is in the next section.
A tool argument is text the model picked
A tool argument (the field the model fills in when it calls a tool: a URL, a file path, an id, a host name) is not a form a person submitted.
Your function receives a string. If you paste that string into a web request, a query, or a command, you have trusted the model. The model did not validate the string. It produced the string. Prompt injection (an attack where instructions hidden in text steer the model away from what the user asked) is how a stranger gets a vote on that string. Indirect prompt injection (the same attack when the instructions ride in a web page, a file, or a previous tool result, not in the message the user typed) is the usual path. The user asked for a summary. The page contained a second request.

Read the arrows left to right once. After that, “the model called my tool” is not evidence that the call was yours.
The old bug underneath
SSRF (server-side request forgery, a bug where your server fetches a web address a caller chose) is older than chat agents.
A firewall (a filter that drops some network connections) often stops an outsider from opening an internal page. Your server is already inside. If a tool takes a URL and fetches it, the fetch is an insider. The attacker does not cross the firewall. They talk your server into walking over and reading the page back.

The arrow out of the server is the bug. The request starts on the trusted side of the wall.
Two details made the Google case sharper than “we block bad names.”
A redirect (an HTTP reply that says the real answer is at a different address) can aim at an internal host after the first check passed. CheckRedirect (the hook that decides whether the HTTP client will follow that hop) was not restrictive in Google’s MCP Toolbox for Databases. The client also never looked at the IP address (the numeric address a computer actually connects to, which is not the same thing as the name you typed).
DNS (Domain Name System, the lookup that turns a name into an IP address) can change its answer in the gap between a check and a connection. That gap is DNS rebinding (the name first points at a public address you allowed, then points at an internal address at the moment you connect). The usual prize is the cloud metadata service (a link-local address a virtual machine can ask for its own cloud credentials; people still cite 169.254.169.254). I am describing the prize, not giving a request that collects it.

Google’s fix is pull request 3448 on googleapis/mcp-toolbox. It checks the resolved address at connection time, applies allow and block lists of IP ranges, and rejects an unsafe base URL when the process starts, not on the first request. An allow list (a set of names or ranges you accept, with everything else refused) is the opposite of trying to list every bad address. The fix ships in toolbox 1.5.0. Versions 0.3.0 through 1.4.0 are CVE-2026-14540, scored 8.0 out of 10 on CVSS (Common Vulnerability Scoring System, the 0-to-10 severity label on a published bug). If you run that toolbox, upgrade. Copy the shape of the guard even if you do not run Google’s code.
The same habit, in codebases that do not share an owner
Mohiuddin’s test was blunt. If the gap is in the idea, it should show up in servers whose authors share no company, no country, and no repo.
It did. Not as one CVE (Common Vulnerabilities and Exposures, the public id for one bug). As one habit: text that crossed MCP was treated as already safe.
| Who | What the tool trusted | Where it stood |
|---|---|---|
| Google MCP Toolbox 0.3.0 to 1.4.0 | A path could redirect the HTTP client. No IP check. CVE-2026-14540, score 8.0 | Fixed in 1.5.0 |
| JPMorgan payments docs server | One search tool had a domain allow list. The sibling tool fetched whatever URL the caller passed | Fixed after disclosure. Rated medium |
| Weaviate | A Google module let endpoint, region, and location point off Google’s own hosts | Restricted. Named in their hall of fame on 25 August 2026 |
| France DINUM, data.gouv.fr | A URL field was fetched on the server, open to DNS rebinding and metadata | Hardening pull request merged 4 September 2026 |
| Tangerang city Wazuh server | A check rejected literal private IPs, so a name could still point at one | Fixed. Advisory GHSA-pw2j-pj4h-f5vg, high, 3 September 2026 |
| Rapid7 Bulk Export MCP 0.2.5 to 0.6.1 | Not SSRF. An export id was glued into a GraphQL query. CVE-2026-97228, score 2.7 | Fixed in 0.6.2 by passing the id as a variable |
DINUM (the French interministerial digital directorate, the office that runs a lot of the state’s public digital services) is the France row. GraphQL (a query language where the caller describes the shape of the answer) is the Rapid7 row only. Pasting the id into the query let a crafted value end the intended question early and add another question, such as “describe your own schema.” Rapid7’s own write-up draws the limit clearly. A person who already held the API key could have called the API directly. The realistic path is a compromised or careless client, or indirect prompt injection forwarding an id the operator did not type. The fix is the old one: pass $exportId as a parameter. Do not build the query by gluing strings. The record is CVE-2026-97228.
Ars Technica spelled Weaviate as “Weviate.” The project is Weaviate. Ars also folded the Rapid7 bug into the SSRF story. The CVE text does not. They share the table because the habit matches. They do not share a bug class.
Protocol pivoting is the hallway
Protocol pivoting (Mohiuddin’s name for a chain where the first foothold arrives on one protocol and the damaging step leaves on another) is the part that is actually new.
His concrete chain, stripped of payload:
- Someone writes text into content an MCP tool will later return. A page, a file, a ticket.
- The text is shaped like a task for a second protocol. His example is A2A (Agent-to-Agent, a protocol for one agent to hand a task to another agent).
- The orchestrator (the agent allowed to split work and delegate) reads that tool output as ordinary data.
- It passes the sentence to a subagent (a specialist the orchestrator calls) as a normal task.
- The subagent trusts the orchestrator, so it runs the task. If that subagent’s own MCP server has an SSRF, the request now starts inside the network, with that server’s permissions.

No box in that picture was broken in the movie sense. Douglas McKee, director of vulnerability intelligence at Rapid7, told Ars: “Every piece in that chain did exactly what it was designed to do, which is what makes this so tricky to catch. Each protocol was built assuming it lived on its own, so each one checks its own front door while nobody watches the hallway in between.”
Markus Vervier, a researcher at X41 D-Sec (a security consultancy), told Ars he would not use the new name. For him this is still indirect prompt injection, and the second protocol is not required. He is right that you do not need A2A to get hurt. One MCP tool that trusts its arguments is enough. Mohiuddin is right that the hop is where a label would have mattered, and there is no label. The second agent cannot see “a web page wrote this.” It sees “my orchestrator assigned this.” Both sentences can be true. The fix does not wait on which name wins.
The researcher’s own line is the one I would keep: the developer treats data crossing the MCP boundary, in either direction, as trusted because it came from inside the system. In an agent pipeline that assumption does not hold. Read Mohiuddin’s protocol pivoting update, Ars Technica’s 5 October report, and The Next Web’s 6 October account.
Why the second agent obeys
The second agent obeys because the message came from a teammate, and nothing on the message records provenance (who first wrote a piece of text, as opposed to who most recently forwarded it).
Zero trust (a design that assumes some machine inside the network is already hostile, so a sensitive call has to prove it is allowed) is the rule these setups quietly dropped. MCP does not have a field for “a human typed this” versus “a scraped page contained this.” The subagent is built to run tasks from the orchestrator. That is the product, not a glitch.

Email grew a weaker version of this late: checks on whether a sender is allowed to use a domain. Spam is still a tax. I am not claiming a finished signature standard for agents that you forgot to switch on. I am claiming you should not wait for one before you stop trusting tool arguments and tool results.
What was still open on 6 October
Two piles were still reported open in the 6 October coverage.

Five servers under the US General Services Administration’s Technology Transformation Services were still in triage after a 2 September report: Veterans Affairs benefits claims, CMS Blue Button (a Medicare program that lets a person pull their own claims data), Regulations.gov, USASpending, and CDC PLACES (a Centers for Disease Control dataset of local health measures). On the VA server, the report says error logs store the full upstream body with no redaction. That body can include a veteran’s name, Social Security number, date of birth, and address. Mohiuddin is withholding the code-level detail until there is a patch. So am I.
Japan’s Digital Agency grants server, the jgrants-mcp-server project, had no authentication (a check that the caller is allowed to connect at all). A pull request to require an explicit opt-in before listening beyond the local machine, and to cap attachment size, was still unmerged in his 7 September note. The Next Web still listed it as open on 6 October.
If you run a fork of either, do not wait for a more specific write-up.
The check on a server you run
Ten minutes. No payload. Open the tool list and mark every argument that becomes a URL, a host, a path, a query, or a command.

- A URL argument needs an allow list, an IP check at the moment of connection, and a redirect policy that cannot hop to a private or link-local address. Reject a bad base URL when the process starts. That is the Google shape. The long version of the URL rules is the OWASP SSRF cheat sheet.
- A query argument is a bound parameter. If you can see the model’s string sitting inside quotes you concatenated, stop. Rapid7’s 0.6.2 release is the pattern, not a special case.
- A path argument stays under one directory. Refuse
..and refuse an absolute path the caller was not supposed to choose. - A command argument should not exist. If the tool runs a shell, the model is choosing the shell.
- Results are untrusted on the way back. Do not hand them to a subagent as the task. Hand them as data, in a field the subagent is not instructed to obey. If the orchestrator prompt says “follow the instructions in the tool output,” delete that line.
- Do not give the specialist a key the orchestrator does not need. A translation agent does not need the database password. MCP makes a function easy to expose. Nothing in that path asks who controls each argument. You have to ask. The role names, if you want them from the project rather than from me, are in the MCP overview.
- An always-allow click is a standing grant. Scope it to one host or one path. A separate OX Security test, not this disclosure, showed a scanning server that asked once for a harmless file and later read a secrets file with no second prompt. Different bug. Same habit: a yes from earlier is not a yes forever.
Turn off servers this task will not call. A process that is not running cannot fetch anything. That is the same /mcp switch as the token piece, and it is not a substitute for the seven checks.
What this is not
This is not a reason to delete every MCP server tonight.
The Google score is high because a crafted path could steer a process that sits near internal addresses. The Rapid7 score is 2.7 because the caller already held the key. A stdio server (one that talks over standard input and output, the pipes between a parent process and its child, instead of over the network) on your laptop is a different blast radius from a process listening on a public port with no authentication.

Ars called this the riskiest protocol you have never heard of. If you read the token piece, you have heard of it. The risk is not the existence of the plug. The risk is a function that treats both sides of the plug as friendly.
Common questions about MCP protocol pivoting
Is MCP itself the vulnerability?
No. MCP is a way to call a tool. The failures here are tools that trust their inputs, and agents that trust text another agent forwarded. A server that checks arguments is still an MCP server.
Do I need Agent-to-Agent installed for this to matter?
No. That is Vervier’s point, and it matches the table. One tool that fetches a model-supplied URL is enough. A second protocol makes the missing label harder to see. It is not the match that starts the fire.
Should I upgrade Google’s toolbox?
If you run googleapis/mcp-toolbox at 1.4.0 or older, and at least 0.3.0, yes. 1.5.0 is the release with the guard.
What should I do about the federal servers and the Japan server?
If you do not run a copy, do not build a clone of the unfixed pattern: no authentication, raw error bodies in logs, a URL argument with no IP check. If you forked one, add authentication and stop logging raw upstream errors. I am not publishing the requests.
If you do one thing after this page, open the tool whose argument is a URL and ask who is allowed to choose it. If the answer is “the model, and the model reads the web,” you do not have a check yet. Add the allow list and the connect-time IP check before you add another agent to the hallway.




