Skip to content

MCP Session Hijacking: Why Session IDs Aren't Authentication for AI Agents

6 min read Fullmakt Team

  • business-case
  • mcp
  • authentication
  • agents
  • observability
  • agentic-ai-gone-wrong

An AI agent connects to a remote MCP server, completes OAuth, and receives a session ID. For the next hour every request carries that ID. Then someone else learns it: from a proxy log, a debug trace pasted into a ticket, or a shared cache. They send a request with the same ID, and the server treats them as the agent.

This is MCP session hijacking, and it is a good example of agentic AI gone wrong for a boring reason. The session ID was treated as proof of identity when it was only a pointer to server-side state.

This post explains how the attack works, what it can do to an agent, and how to design MCP and A2A deployments so a stolen session ID is worth very little.

What an MCP session is

The Model Context Protocol’s streamable HTTP transport can run in a stateful mode. The server hands the client an Mcp-Session-Id header after initialization, and the client sends it back on later requests. The server uses it to find per-session state: negotiated capabilities, subscriptions, and queued events for a resumable stream.

The MCP specification says sessions must not be used for authentication. Servers should verify every inbound request, and session IDs should be secure and non-deterministic. Many implementations get the second part right and skip the first.

The attack patterns

  • Session takeover. An attacker with a valid session ID replays it with their own requests. If the server only checks that the ID exists, the calls run with the victim’s tools and permissions.
  • Event injection. In multi-node deployments with a shared queue, an attacker who knows an ID can have a malicious server-sent event delivered to the victim’s open stream. The agent then receives a “tool result” or notification it never asked for. That is a delivery channel for indirect prompt injection.
  • Context bleed. If an ID is reused or collides across users, one person’s state is served to another. See cached tokens and cross-user session bleed.
  • Silent persistence. A long-lived session outlives the OAuth token that created it. Revoke the user, and the session may still answer.

None of these needs a model exploit. They are ordinary web-session bugs, with the difference that the “user” on the other end is an autonomous agent that will act on whatever arrives, without a person noticing something odd.

Why agents raise the stakes

A hijacked browser session exposes what a person can click. A hijacked agent session exposes what the agent can call, at machine speed, with no pause for second thoughts. If the agent’s tools hold credentials, a stolen session can spend, delete or exfiltrate before anyone looks at a log.

It is also hard to see. A hijacker’s requests share the victim’s session, so your logs show the legitimate agent doing something strange. Without per-call attribution you cannot separate the two. That is the traceability gap that makes incident response slow.

Design rules that limit the damage

  1. Authenticate every request, not the session. Validate the bearer token on each call. Bind it to the right audience, as covered in token passthrough and audience binding.
  2. Prefer stateless servers where you can. If the server needs no per-session state, there is no session ID to steal. Stateless transport is often enough for request/response tool calls.
  3. If you need state, bind it to identity. Key session state by (user or principal, session ID), never the ID alone, and reject a mismatch.
  4. Keep sessions short, and tie them to token lifetime. Revoking access must end the session. See refresh tokens for AI agents.
  5. Sign the action, not just the connection. A per-call signature stops a hijacker from forging arguments. See signed task envelopes.
  6. Never let the agent hold the upstream secret. Then even a hijacked session cannot read a key out of context.

How Fullmakt approaches it

Fullmakt is a credential broker for AI agents. Agents reach it over MCP or A2A. It enforces policy, attaches the upstream credential on the server side, and records an audit entry for each call.

  • Stateless MCP transport. Fullmakt’s first-party MCP server is configured with the stateless HTTP transport, so it does not issue a session ID that an attacker could replay. Authentication happens on each request.
  • Credentials stay server-side. The agent calls a tool; the broker resolves the credential reference and makes the upstream request. A hijacked connection yields access to the tools policy allows, not to the secret.
  • Policy on every call. Allow, deny and require-approval decisions run per request, so a takeover cannot skip the gate that a normal call passes through.
  • Per-call audit. Each execution is attributed to an agent principal and recorded, which is what lets you tell an agent’s behaviour from an impostor’s.
  • Optional signed envelopes let you require proof that each call’s arguments are the ones the agent signed.

This does not make a stolen bearer token harmless; revoke and rotate it. What the design does is reduce the blast radius: scoped tools, no raw secrets, a decision and a log entry per call.

The business case

Session hijacking is the kind of finding that appears in a customer security review or a penetration test report. Being able to say that your agent platform authenticates each request, keeps secrets out of the agent, and logs every call shortens those reviews. It also gives incident responders a trail when something does go wrong. Compare the cost of building this yourself in build vs buy for an agent credential proxy.

Checklist

  • Does your MCP server need sessions at all? If not, run it stateless.
  • Is every request authenticated and audience-checked, or only the first?
  • Is session state keyed by identity as well as ID?
  • Does revoking a token or user end open sessions?
  • Can you tell a hijacker’s calls from the real agent’s in your logs?
  • Do agent tools ever hold a raw secret that a takeover could read?

FAQ

What is MCP session hijacking? Using a captured Mcp-Session-Id to send requests as another client, or to inject events into their stream, because the server trusts the ID instead of verifying the caller.

Are MCP session IDs secrets? Treat them as sensitive, but don’t rely on them. The spec says sessions must not be used for authentication; every request needs its own authorization.

Does a stateless MCP server fix this? It removes the session ID as an attack target. You still need per-request token validation, audience binding and policy.

Does it stop prompt injection? No. It closes one delivery channel. Combine it with scoped credentials, policy and approvals.

Does Fullmakt support MCP and A2A? Yes. Agents connect over MCP or A2A, and every call passes policy and is audited.

What does Fullmakt cost? Usage-based pricing per operation, with no plans or minimums, plus a no-card sandbox for trying it with your own agents.