41% of MCP Servers Have No Auth — Here's How to Fix Yours

Nearly half of all publicly accessible MCP servers run with no authentication. Step-by-step implementation, real CVEs, and a security audit checklist.

MK

Mohammed Kafeel

Machine Learning Researcher

June 18, 202614 min read
On this page

MCP server authentication isn't optional - but for nearly half of all deployed servers, it's missing entirely. Endor Labs found that 38–41% of MCP implementations have no authentication mechanism whatsoever. A July 2025 internet scan by the Cloud Security Alliance found 1,862 publicly accessible MCP servers responding to unauthenticated tool-listing requests.

That's 1,862 open doors, already mapped by threat actors.


What Is MCP Authentication (and Why Does It Matter)?

MCP (Model Context Protocol) is an open standard from Anthropic. It gives AI agents like Claude, Cursor, or Windsurf a structured way to connect to external tools.

Authentication means: proving who is making a request before you let them do anything. Without it, anyone who can reach your server can call your tools.

The MCP spec marks authorization as OPTIONAL by design. The protocol was originally built for local use - a developer running tools on their own machine. That made sense in 2024. It's a liability in 2025.

The spec does define an OAuth 2.1 framework for HTTP-based transports. But "optional" means many teams skip it.


What Can Go Wrong Without Authentication?

Without authentication, any internet user can call your MCP tools. No login, no token, no permission check.

Real Risks, Ranked by Severity

Risk Severity Real-World Example
Unauthenticated access Critical CSA scan: 1,862 servers exposed tool listings with zero credentials
Command injection Critical CVE-2025-6514 (CVSS 9.6): arbitrary OS command execution via mcp-remote
Remote code execution (RCE) Critical CVE-2025-49596 (CVSS 9.4): unauthenticated RCE on MCP Inspector host
Tool poisoning (TPA) High CVE-2025-54136: config poisoning via repository commit
Prompt injection High Hidden instructions in tool descriptions manipulate the AI agent
Confused deputy attacks High Attacker tricks server into acting on their behalf
Data exfiltration High Supabase-Cursor incident (July 2025): SQL injection via support tickets leaked tokens

The CVEs You Need to Know

  • CVE-2025-6514 (mcp-remote, CVSS 9.6): Unauthenticated command injection. Affected 437,000+ downloads.
  • CVE-2025-49596 (MCP Inspector, CVSS 9.4): No authentication between browser client and proxy. Full RCE on developer workstation. Fixed in v0.14.1.
  • CVE-2025-54136 (Cursor IDE / MCPoison): Configuration poisoning via repository commit.
  • CVE-2025-53967 (Figma Developer MCP): Command injection leading to RCE.

Prompt injection ranks as the #1 MCP vulnerability by Adversa AI - impact 10/10, exploitability trivial, prevalence universal.


The 41% Problem: Why So Many MCP Servers Skip Auth

Most developers who skip auth aren't being reckless - they're being fast.

Root Causes

  • MCP was designed for local use. STDIO transport was built for a developer on their own machine.
  • Auth adds friction. OAuth 2.1 flows, token validation, redirect URI matching - real work.
  • The spec says it's optional. When the spec marks authorization as OPTIONAL, it signals skipping is acceptable.
  • Lack of awareness. By mid-2025, MCP had 150 million+ package downloads. Most developers weren't security engineers.

The numbers:

  • Endor Labs: 38–41% of MCP implementations had no auth
  • CSA scan (July 2025): 1,862 publicly accessible unauthenticated servers
  • Adversa AI: 43% of MCP servers vulnerable to command injection

How to Add Authentication to Your MCP Server (Step-by-Step)

Step 1: Choose Your Auth Method

Method Use Case Complexity Security Level
OAuth 2.1 Public-facing, multi-client, production Medium–High ⭐⭐⭐⭐⭐
API Keys Internal tools, simple integrations Low ⭐⭐⭐
JWT Stateless M2M, multi-tenant Medium ⭐⭐⭐⭐
mTLS Enterprise, zero-trust, regulated High ⭐⭐⭐⭐⭐

The MCP spec recommends OAuth 2.1. For public-facing servers, start there. Session-based auth is explicitly prohibited. (For the full PKCE walkthrough, see implementing MCP OAuth 2.1.)

Your MCP server acts as an OAuth 2.1 resource server.

The core flow:

1. Client sends request to MCP server (no token yet)
2. MCP server returns HTTP 401 with WWW-Authenticate header
3. Client discovers auth server from Protected Resource Metadata (RFC 9728)
4. Client initiates OAuth 2.1 Authorization Code flow with PKCE
5. Auth server issues access token (short-lived, audience-bound)
6. Client sends request with: Authorization: Bearer <access-token>
7. MCP server validates token (signature, expiry, audience, scopes)
8. Tool executes - or returns 403

Implementation requirements:

  • PKCE is mandatory (use S256)
  • Implicit grant is forbidden
  • Exact redirect URI matching
  • Validate state parameter
  • Serve Protected Resource Metadata at /.well-known/oauth-protected-resource
import jwt
from fastapi import HTTPException, Security
from fastapi.security import HTTPBearer

security = HTTPBearer()

def validate_token(token: str) -> dict:
    try:
        payload = jwt.decode(
            token,
            key=get_public_key(),
            algorithms=["RS256"],
            audience="https://your-mcp-server.example.com",
            options={"verify_exp": True}
        )
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidAudienceError:
        raise HTTPException(status_code=401, detail="Invalid audience")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")

Step 3: If Using API Keys - Store Them Safely

  • Never hardcode keys in source, config, Dockerfiles
  • Store in environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault, 1Password)
  • Rotate every 30–90 days - automate
  • Scope keys explicitly - one key per client, per environment
  • Pass keys in headers only - Authorization: Bearer or X-API-Key
  • Hash keys at rest using bcrypt or scrypt
# Good: load from environment
export MCP_API_KEY="$(vault kv get -field=key secret/mcp/prod)"

# Bad: hardcoded in code
MCP_API_KEY = "sk-live-abc123..."  # ❌ Never do this

Step 4: Validate Every Token - No Exceptions

For every inbound request:

  1. Signature - verify against JWKS
  2. Expiry (exp) - reject expired immediately
  3. Audience (aud) - must be issued for your MCP server
  4. Issuer (iss) - must match your trusted auth server
  5. Scopes - must include scopes required for the tool

Audience validation is mandatory per RFC 8707. Token passthrough is explicitly forbidden - obtain new tokens for upstream services.

Step 5: Enforce HTTPS/TLS on All Connections

Never run an MCP server over plain HTTP in production.

  • TLS 1.2 minimum; TLS 1.3 preferred
  • Redirect HTTP to HTTPS
  • Valid certificate from a trusted CA
  • For enterprise: consider mTLS
  • Issue tokens with minimum scopes
  • Enforce scope checks per tool endpoint
  • Require explicit user consent for high-privilege scopes
  • Implement per-client consent tracking - prevents the MCPoison attack
  • Re-prompt for consent when tool definitions change

For tighter control, layer per-tool access control on top of scopes so each agent role can only invoke the tools it actually needs.

Example scope structure:

files:read       → can read files
files:write      → can write files
db:execute       → can run database queries
secrets:read     → can access secrets (high privilege)

5 MCP Security Rules You Should Never Break

  1. Never use session-based authentication. The MCP spec prohibits it.
  2. Never pass tokens through without validation. Token passthrough is forbidden.
  3. Always validate the token audience. Validate aud on every request. No exceptions.
  4. Always enforce HTTPS. TLS is table stakes.
  5. Rotate credentials regularly. API keys every 30–90 days. Short-lived JWTs (5–30 min). Automate.

Even with auth locked down, you need visibility into who called what - set up audit logging for MCP so every tool invocation is recorded.


Quick Security Audit Checklist

# Check Status
☐ 1 Auth enabled on all endpoints - no tool callable without valid token
☐ 2 Tokens validated for audience + expiry + signature
☐ 3 HTTPS enforced on all connections
☐ 4 No hardcoded secrets anywhere
☐ 5 Credentials rotated in the last 90 days
☐ 6 Token passthrough disabled
☐ 7 Session-based auth not in use
☐ 8 Redirect URIs exactly matched
☐ 9 Per-client scopes enforced
☐ 10 Tool definition changes require re-consent

If you checked all 10, your MCP server is in better shape than at least 41% of the ecosystem. (For controls beyond auth, work through the full MCP security checklist.)


FAQ

OAuth 2.1 for HTTP-based transports, per the MCP specification. It requires PKCE with S256, exact redirect URI matching, and mandatory token audience validation via RFC 8707.

Is OAuth 2.1 required for MCP servers?

Not strictly - the spec marks authorization as OPTIONAL. But for any network-accessible MCP server, treating OAuth 2.1 as required is the right call. CSA, NSA, and Endor Labs all recommend mandatory auth for remote MCP server connections.

What happens if my MCP server has no authentication?

Any internet user who can reach your server can call your tools. Attackers can enumerate your tool list, trigger executions, inject prompts, exfiltrate data, and potentially achieve RCE.

How do I store API keys securely for MCP servers?

Environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault, 1Password). Pass via Authorization: Bearer headers - never URLs. Hash at rest. Rotate every 30–90 days.

What is a "confused deputy" attack in MCP?

When an attacker tricks your MCP server into using its own authority to act on their behalf. They send a request with a token not issued for your server. If your server doesn't validate the audience - or forwards the token upstream - the upstream API sees a request appearing to come from your trusted server. The MCP spec forbids token passthrough to prevent exactly this.


Useful Sources