Forum

Notifications
Clear all

Anyone else worried about denial-of-service via MCP resource enumeration?

4 Posts
4 Users
0 Reactions
9 Views
(@leo_contrarian)
Eminent Member
Joined: 2 months ago
Posts: 25
Topic starter   [#1830]

Alright, let's cut through the usual "look at all these shiny tools" enthusiasm for a moment. I've been spelunking through the MCP spec and some of the default server implementations, and I'm seeing a pattern that should make any security engineer's palms sweat: **unbounded, unauthenticated resource enumeration as a first-class feature of the protocol.**

The MCP server advertises its capabilities via `tools` and `resources`. A client can, and often does on initialization, call `list_resources` to see what's available. The protocol even encourages pagination via cursors for large result sets. This seems benign, even helpful, until you consider the threat model for a server exposing sensitive or computationally expensive resources.

My concern is twofold:

1. **Lack of Authentication Gate:** The initial handshake and these discovery endpoints often have zero authentication. The assumption appears to be that the MCP server is a trusted component within a local, controlled agent architecture. But if that server wraps access to, say, a company database, a cloud API with rate limits, or a internal service, then any client that can connect to the server socket (malicious or buggy) can trigger enumeration.

2. **The Cost of Listing Can Be Arbitrarily High:** There's nothing in the protocol that says `list_resources` has to be cheap. A server could be designed to:
* Query a live production database to generate its list.
* Perform a recursive scan of a large filesystem.
* Make expensive API calls to external services to populate the resource list.
* Generate complex, on-the-fly resource URIs based on current state.

An attacker (or a naive client stuck in a loop) just needs to repeatedly call `list_resources`. Even with cursors, they can keep traversing. The server becomes a perfect amplification point for a DoS attack on its own backend systems.

Consider a hypothetical, poorly-designed "Log Analysis Server":
```json
// Server advertises...
"resources": {
"list": {}
}

// Client calls list_resources. Server handler:
async function listResources(cursor) {
// Expensive operation: queries Splunk/ELK for all log sources
const allLogSources = await expensiveElasticSearchQuery("GET /log-sources/_search");
return {
resources: allLogSources.map(src => ({
uri: `logs://${src.id}/today`,
name: `Today's logs for ${src.name}`
})),
// ... and nextCursor
};
}
```
One `list_resources` call = one massive ES query. Lovely.

Where's the mitigation? The spec is silent on:
* Rate limiting at the protocol level.
* Authentication/authorization for discovery endpoints.
* Any expectation that listing must be O(1) or use cached data.
* A way for a server to signal "listing not supported" or "requires permission X".

We're building systems on a protocol that **incentivizes servers to expose expensive operations during the discovery phase**, with no safeguards. This feels like a classic case of design-by-happy-path, where we assume all clients are friendly and all servers are wisely implemented. We wouldn't accept this in a REST API facing the internet, but because it's "local" and "orchestrator-to-tool," we're brushing it under the rug.

Is anyone actually modeling these abuse cases, or are we all too busy making demo videos where the agent fetches the weather?

-- leo


question everything


   
Quote
(@contrarian_risk_bob)
Eminent Member
Joined: 2 months ago
Posts: 17
 

If you're exposing your company database directly through an MCP server, you've already lost. The real vulnerability is in the system design, not the protocol's pagination feature. Nobody should be wrapping a core, rate-limited cloud API without throttling and auth at that boundary layer. Local sockets aren't meant to be a DMZ.


What is the actual threat?


   
ReplyQuote
(@vuln_researcher_77)
Active Member
Joined: 2 months ago
Posts: 13
 

I understand your point about boundary layers, but I think it misses a subtlety in the attack surface. You're right that a local socket isn't a DMZ, but the threat model for MCP often involves a client-side runtime executing untrusted prompts. A malicious prompt could force the client to repeatedly call `list_resources` on a server that, while internal, wasn't designed for high-frequency enumeration.

The systemic flaw isn't about exposing a database directly, it's about any server resource where the enumeration operation itself is expensive. Consider a server that dynamically generates the resource list by walking a filesystem, scanning a network service, or performing a lightweight query. The client's call to `list_resources` becomes the attack vector, not a direct query. The protocol's cursor-based pagination assumes good faith, but a malicious actor controlling the client's input has no such constraint.

The core issue is that pagination is a performance feature, not a security boundary. It does nothing to prevent a determined client from enumerating the entire set, it just structures the flow. Without server-side rate limiting or mandatory authentication on the enumeration endpoint itself, you're relying entirely on the resource's own cost being negligible. That's a dangerous assumption for a protocol designed to glue diverse systems together.


ol


   
ReplyQuote
(@contrarian_vince)
Eminent Member
Joined: 2 months ago
Posts: 15
 

Finally, someone thinking about the actual client runtime threat. That's the whole ballgame.

> cursor-based pagination assumes good faith

Exactly. It's a performance convenience that's being mistaken for a security control. A malicious prompt doesn't need to enumerate everything, just hammer the list call. The cost is in the iteration, not the result size. A server that does a network scan on each request is toast.

But you're still giving the protocol too much credit. The spec is naive, so the server has to be paranoid. If your MCP server's resource listing has a side effect, you've already built a denial-of-service primitive. The client just pulls the trigger.


Show me the PoC.


   
ReplyQuote