Back to Blog

New MCP Spec Opens Three New Attack Surfaces. Security, Get Ready.

-

May 28, 2026

Maya (Mayo) Pik

May 28, 2026

The Model Context Protocol (MCP) just rewrote how AI agents connect to everything. Before the final spec drops on July 28th, here is what is changes and why it matters for security at the endpoint layer.

The next version of MCP eliminates stateful sessions in favor of portable handles, deprecates the Roots capability, and introduces MCP Apps, a new extension that lets servers ship interactive HTML interfaces directly to AI agents. These three changes in the expected final spec, are expected to create new attack surfaces at the endpoint layer, invisible to network, and to gateway-based security tools.

A true story as documented in AuthZed's timeline of MCP security incidents:

An agent was given a routine task to generate a usage report. No one had set filesystem boundaries. The agent completed the task. It also accessed 340 other files along the way, credential stores, .env files with database passwords, Stripe API keys, and AWS secrets. Then, in a subsequent tool call, it exfiltrated them to an external webhook.
The agent wasn't “hacked”. It wasn't doing anything wrong by its own logic.
It just had no boundaries, and with the new MCP architecture, the mechanism that used to create those boundaries no longer exists.


That is what the MCP update on July 28th changes.

MCP Goes Stateless. The State Moves Into the Conversation.

MCP, since its launch has been stateful. An agent connects, completes a handshake, and receives an Mcp-Session-Id header. Every subsequent request carries that header. It's the same server, and it remembers who you are. The new spec changes this completely. No handshake. No session ID. Every request is standalone.

The state did not disappear. It just moved - but where to?

Think of statefulness as the difference between a members-only club and a food festival.
The club remembers you: the bouncer knows your face, your table is waiting, the staff knows your order. But you have to come back to the same club, the same door, the same bouncer - every time. These are sticky (i.e., stateful) sessions. The crowded festival, on the other hand, doesn't remember you at all. But you're holding a ticket. You can walk up to any stall, show the ticket, and get served. The state travels with you. Any server can handle any request because everything they need is printed on the pass you're carrying.

The catch: At the club, the bouncer held the credential. You could lose it or leave it somewhere, and you’d still be recognized and let in. At the festival, the ticket is in your pocket.

In the old MCP, the session ID traveled inside the HTTP header, the invisible "envelope" of every request. The AI model never saw it, never touched it, and so could never leak it. It worked behind the scenes, like the cookies your browser sends without you ever reading them.

In the new version, there are no headers carrying state. Instead, when an agent calls create_browser(), the server returns a "handle" directly inside the conversation: { "browser_id": "browser-abc123" } That string is now part of the chat. The AI sees it, holds it, and must pass it in every subsequent call: navigate(browser_id: "browser-abc123", ...), click(browser_id: "browser-abc123", ...), and everything in a conversation can end up in the wrong hands - a Jira ticket, a Slack message, a shared transcript. In the old MCP, that was useless. The session ID wasn't there. Starting July, the handle is right there in the conversation. And whoever has the string can now gain access.

The engineering motivation is clear: stateless architecture scales, and for infrastructure teams building multi-tenant agent platforms, this is a genuine win.

But the state didn't disappear. It just moved into the conversation. And security teams should adapt to this new reality. Actually, three new realities.

a tighter one if you want minimal: Before, state lived in the server's memory. After, it travels with the agent as a portable handle, and any node can serve any request.
July 26: MCP changes from Stateful to Stateless: architecture diagram

Reality 1: Handle Hijacking Replaces Session Hijacking

Session hijacking needed access to the server's session store. Handle hijacking needs access to the conversation. The handle is just a string the model can see, echo, and pass along, with no built-in binding to user, IP, or TLS.
Reality 1 table, Handle Hijacking

The attack surface is exactly what you would expect. A malicious tool response can tell the model to use an attacker-controlled ID: the server returns { "task_id": "t-ATTACKER-CONTROLLED" } and the model obeys.
No CVE filed. No exploit deployed. The protocol did exactly what it was designed to do, and handed the attacker full access.

A handle from one user's conversation can be replayed in another user's request if the server does not validate the (handle + auth context) pair, not just the handle alone. And the requestState blob, which servers echo back to track multi-step operations, can be tampered with before it returns: change the transaction amount, change the recipient. If the server trusts the echo without verification, you’ve been infiltrated.

Session-based (old MCP) Handle-based (new MCP)
What the credential looks like Opaque session token, server-managed Portable handle string, client-held
Where it lives Server memory / session store Inside the conversation context
What an attacker needs Access to server session store Access to the conversation (prompt, tool output, logs)
Replay risk Limited, server can invalidate session High, handle is valid anywhere until the resource expires

The next two realities are independent of the stateless shift. They come from separate changes in the same release, one from how the spec handles filesystem scope, the other from a new extension entirely. Different causes, same implication: your existing security tooling can't see either of them.

Reality 2: The Filesystem Scope Gap

With Roots deprecated, the protocol's one structural filesystem boundary is gone. Scope enforcement now lives in each developer's code, applied inconsistently. Backslash research documented what agents do when that boundary is only a convention.
Reality 2, filesystem scope gap

Until now, the best practice when installing an MCP was to restrict which filesystem paths an AI agent could access, enforced by the Roots capability. Now it no longer exists. Without it, scope enforcement is no longer structural. It is opt-in, applied inconsistently by individual server developers, and undetectable by any gateway tool. An agent can access credential stores, .env files, and API keys that have nothing to do with its assigned task - and the protocol will not stop it.

Why? The Roots listing capability cannot persist once the initialize handshake is removed. With no session, every request arrives standalone - no shared state, no natural enforcement point. Scope boundaries stop being the protocol's problem and become the MCP server developer's problem.

The protocol lost its one structural enforcement point - and with it, the guarantee that no server could silently reach beyond its intended scope.

The spec's replacements - tool parameters, resource URIs, server-side configuration - are all valid approaches. They are also all opt-in - not enabled by default. Enforcement is now the responsibility of each individual MCP server developer, applied inconsistently across a fragmented ecosystem.

What can an agent access without Root enforcement?

The risk class this opens is not hypothetical. Before this new architecture came about, security researchers documented what agents do when filesystem scope is enforced only by convention:

An agent tasked with generating a usage report accessed 340 files before completing the task - including credential stores that had nothing to do with the report. An agent reading logs for a debugging task found .env.production on its path, read DB passwords and Stripe API keys, and exfiltrated them to an external webhook in a subsequent tool call. An agent running a file cleanup task wrote a beacon to ~/.bashrc that executed on every subsequent shell session -persistence without a separate implant stage.

In each case, the agent was not breached. It was used exactly as intended. The scope was just never enforced. The question for your team is not whether your MCP servers have good intentions. It is whether filesystem scope is structural or aspirational in each one.

Reality 3: Your IDE Now Renders Server HTML

MCP introduces a new extension called MCP Apps (SEP-1865). MCP Apps is an opt-in extension - not every server exposes this surface. But those that do present a new category of risk. Servers that implement it can ship interactive HTML that renders inside a sandboxed iframe directly in your IDE. When a user clicks a button in that iframe, it fires a JSON-RPC tool call back to the server.

The use cases are obvious. Inline auth flows. Configuration UIs. Approval dialogs that keep the developer in their editor. The ergonomics are real.

What can a malicious MCP App do inside your IDE?

The trust inversion is the problem. On the web, you choose what to trust - your browser enforces origins, and decades of hardening stand between a page and your machine. Here, that decision was already made the day you ran mcp install.

The rendering context is not a browser tab. It is your IDE - your source code, terminal, filesystem, and every connected MCP server. A sandbox escape in a tab costs you that tab. A sandbox escape here is a full IDE compromise.

The attack surface is the iframe itself - a server-controlled rendering context inside your IDE. The potential attack vectors: XSS, clickjacking, supply chain poisoning through malicious UI templates. And the most specific threat - UI mimicry. whereby a server ships HTML identical to VS Code's native auth prompt. A developer types their credentials in ,and they just handed their login credentials to a server-rendered form.

None of this touches the network.

All of the above happens on the endpoint, with no visibility from the network.

Security gateways sit on the network. They inspect HTTP traffic. But a handle string passed inside an AI conversation is not inspectable at the network layer. Filesystem access on a developer's local machine never touches the network gateway. HTML rendering inside a VS Code iframe is not network traffic. None of these three threats generate the signals that gateway tooling was built to detect.

This is not a limitation of any specific gateway product. It is architectural. Gateways were built for a different threat model. The three new attack vectors made possible by MCP 2026-07-28 happen on the endpoint - on the developer's machine, inside their IDE, inside the tool they installed and trusted at the protocol level.

Only endpoint software can see what gateways cannot.

That is the gap Backslash is built to close.

Only software that runs on the endpoint, watching the host process, observing local MCP servers, inspecting what renders in the IDE - can see these threats before they become incidents. Gateway visibility stops at the network boundary. These threats start on the other side of it.

The new spec is moving security to the endpoint layer, whether your security team is already there or not.

Before July 28th: Four Things Worth Checking Now

The final MCP 2026-07-28 spec will be published on July 28th. The validation window opened May 21, 2026 - giving the ecosystem 10 weeks to ship support before the spec is finalized on July 28th. Tier 1 SDKs are expected to ship support during the validation window. Ecosystem adoption accelerates from that date. The window to get ahead of this is measured in weeks.

Four checks worth running before that date:
  1. Check whether handles are tied to a specific user.
    It's not enough to have the handle string - the server should also verify that the person using it is the same person who created it. A server that accepts any handle without checking who's asking is open to replay attacks: someone grabs the string from a Jira ticket and uses it themselves.
  2. Check whether handles expire.
    A handle that works forever is a permanent access token. If a developer leaves the company, changes their permissions, or their session ends - the handle should stop working too. If your MCP servers have no expiry policy, that's a gap.
  3. Map which MCP servers run locally on developer machines.
    Any server running locally is invisible to network monitoring. Your security team needs to know which servers in your stack operate on-device - because no gateway or network tool will ever surface an issue from them.
  4. Inventory MCP Apps exposure.
    Find out which MCP servers your team uses that can ship HTML UI into the IDE. Before this becomes standard practice, establish a policy for reviewing what HTML gets rendered - the same way you'd review a third-party script on your website.

To reiterate, the spec is good engineering. The scale argument is real.
But the security work that used to happen at the session layer now has to happen on the endpoint, deliberately and explicitly, by design.

The spec moved on, changing what can and see. The question is whether your security posture moves with it, and if not, there is no better time than now to avoid putting your organization at risk.

Questions you should ask about the new MCP specs

When does the new MCP spec go live, and do I need to act before July 28th?

The final spec publishes on July 28, 2026, with the validation window already open since May 21st. Tier 1 SDKs are expected to ship support during that window, and ecosystem adoption accelerates from there. You don't need to migrate anything yourself, but it's worth using these weeks to inventory which MCP servers your team uses, which run locally vs. remotely, and which can already render HTML into the IDE.

Will my existing security gateway or network DLP catch these new risks?

No, and that's an architectural point, not a product critique. Handle strings passed inside an AI conversation aren't visible at the HTTP layer. Filesystem access on a developer's laptop never crosses the network gateway. HTML rendered inside an IDE iframe doesn't generate network traffic. Detecting any of these requires visibility into the host process, the local MCP server, and what's rendering inside the IDE.

Does this affect only local MCP servers, or hosted/remote ones too?

Both, in different ways. Handle hijacking and tampered requestState blobs apply to any MCP server, local or remote, anywhere a handle ends up in a conversation that can be replayed or leaked. The filesystem scope gap and MCP Apps rendering risks hit hardest on local servers, where the IDE, source code, and credential stores live. Either way, none of it is visible from the network.

Is MCP Apps enabled by default, or do server developers have to opt in?

MCP Apps (SEP-1865) is opt-in, so not every server exposes it. But for the ones that do, the rendering context isn't a browser tab with origin enforcement. It's your IDE, with access to source code, terminal, filesystem, and every other connected MCP server. That's why MCP Apps deserves its own review policy, the same way you'd vet a third-party script before adding it to a production site.

How is handle hijacking different from prompt injection?

They often travel together but they're distinct. Prompt injection is the technique, untrusted content steering the model's behavior. Handle hijacking is the outcome the new spec makes possible: once a handle is in the conversation, anyone who can plant or read that string can use it. A prompt-injection payload in a Jira ticket or tool response can hand an attacker a valid handle without ever touching the server. Defenses for one don't cover the other, so you need both conversation-layer hygiene and per-request handle validation.