# Why 95.8% of OAuth MCP Servers Risk Redirect URI Phishing

*Updated on November 4, 2026*

As enterprises connect Model Context Protocol (MCP) servers to production S3 buckets, GitHub repositories, payment processors, and internal SSO gateways, a fundamental flaw in how MCP implements OAuth Dynamic Client Registration is exposing organizations to one-click account takeovers. According to a security architecture analysis published on November 4, 2026, by Stream Vessel engineer Alexander Loginov, `95.8%` of tested OAuth-enabled MCP servers (`114 out of 119`) accept arbitrary `redirect_uri` values from anonymous requesters during client registration.

The vulnerability stems from a sharp collision between the decentralized design of MCP and traditional OAuth 2.0 security assumptions. When a developer spins up a custom MCP client—such as a self-hosted Slack agent or a VPS automation worker—the client uses OAuth Dynamic Client Registration to introduce itself to the MCP server and specify its callback address (`redirect_uri`), where the user's browser should deliver the one-time authorization code after clicking **Approve**.

Because an MCP server operator does not know every self-hosted agent domain in advance, `95.8%` of deployments leave dynamic registration open to any URI. That open policy allows an unauthenticated attacker to register a fake client named `"Claude"`, set its `redirect_uri` to `https://evil.example/cb`, and send a victim a legitimate `/oauth/authorize` link hosted on the real MCP server's domain.

When the signed-in victim sees their real provider's consent screen asking to connect `"Claude"` and clicks **Approve**, the authorization server delivers the OAuth code directly to the attacker's server. Even worse, **PKCE (Proof Key for Code Exchange) offers zero protection against this attack**, because PKCE only verifies that the entity finishing the OAuth flow is the same entity that initiated it—and in this attack chain, the attacker initiated the flow.

<a aria-hidden="true" id="executive-fast-facts"></a>  Fast Facts

- **Empirical Vulnerability Rate**: `95.8%` (`114 of 119` OAuth-enabled MCP servers tested in a 2026 security survey) accepted arbitrary `redirect_uri` endpoints from anonymous dynamic registrations, as analyzed in the [Stream Vessel MCP OAuth engineering report](https://streamvessel.com/blog/mcp-trusted-redirect-uris).
- **Real-World Exploit Precedent (Square MCP)**: In January 2026, Obsidian Security disclosed this exact chain against Square's MCP server, where open dynamic registration allowed a single click to expose merchant profiles, transaction histories, and bank details.
- **Enterprise SSO Proxy Exposure**: Security researchers discovered the same open-registration redirect flaw on an enterprise MCP SSO proxy, yielding a `24-hour` access token and `14-day` refresh token from a single click, plus an `RFC 9700` open-redirector flaw on failed scope checks.
- **The Closed-Allowlist Dilemma**: Locking an MCP server down to a static operator allowlist (only permitting `Claude`, `ChatGPT`, `Cursor`, and `VS Code` callback URLs, as Atlassian and GitHub do) blocks developers from connecting their own self-hosted MCP agents.

## Security Trade-Off Matrix: MCP OAuth Redirect URI Architectures

How can an MCP server operator block anonymous `"Claude"` impersonation and open redirects (`RFC 9700`) without locking out engineers who run their own custom MCP clients on private domains?

| OAuth Registration Policy | Vulnerable to 1-Click Consent Phishing? | Supports Custom Self-Hosted MCP Agents? | Vulnerable to RFC 9700 Error Open Redirect? | Real-World Examples |
|---|---|---|---|---|
| **Open Dynamic Registration (95.8% of Servers)** | **YES (Critical — PKCE does not block)** | Yes | **YES** (Invalid scope redirects to attacker URI) | 114/119 audited MCP servers; pre-patch Square MCP |
| **Static Operator Allowlist Only** | No | **NO** (`invalid_redirect_uri` for custom agents) | No | Atlassian MCP, GitHub MCP (requires OAuth App) |
| **User-Pinned Trusted Redirect URIs** | **NO (Bound to authenticated user session)** | **YES (Users allowlist their own agent URIs)** | **NO** (Unverified URIs rejected pre-redirect) | Stream Vessel MCP OAuth architecture |

## Why User-Scoped Redirect URI Pinning Solves Both Halves of the Problem

As Loginov demonstrates, the clean architectural fix is to move trust for custom `redirect_uri` endpoints from **anonymous dynamic registration** to the **authenticated user's account settings**. Under a user-pinned model:

1. **Global Operator Allowlist for Major Hosts**: Well-known official clients (`Claude`, `ChatGPT`, `Cursor`, `VS Code`) remain on the server's global verified allowlist with cryptographically bound redirect domains.
2. **User-Scoped Personal Allowlist for Custom Agents**: If an engineer wants to connect a self-hosted agent at `https://agent.myhost.example/callback`, they first add that exact URI inside their authenticated dashboard (or verify it via a secondary out-of-band confirmation step).
3. **Strict Pre-Flight Matching**: When `/oauth/authorize` is called, the server checks that the requested `redirect_uri` either matches the global verified list or belongs to the **currently logged-in user's personal pinned URI list**. An attacker's `https://evil.example/cb` is rejected before the consent screen ever renders, and errors never redirect to unverified hosts.

  Next Steps

1. **Audit Your MCP Server `/register` and `/authorize` Endpoints Immediately**: Test whether an unauthenticated `POST` to your MCP server's dynamic client registration endpoint can register `client_name: "Claude"` with an external `redirect_uri`.
2. **Never Redirect OAuth Error Responses to Unverified URIs**: Per `RFC 9700`, ensure your authorization server renders error pages locally if a `redirect_uri` or scope check fails rather than redirecting the user's browser to the supplied callback.
3. **Implement Per-User Trusted Redirect URI Pinning**: Replace open anonymous redirect registration with a user-scoped allowlist so developers can register custom VPS or Slack MCP agents safely without opening a cross-user phishing hole.