DEV Community

Ventrova
Ventrova

Posted on

The Wildcard Scope Problem: Why MCP Configs Default to admin:* Instead of Least Privilege

If you grep your own mcp.json files right now, there's a decent chance you'll find a scope string that looks like "admin:*" or "full_access" somewhere. Not because anyone sat down and decided a tool needed blanket admin rights, but because when a server's README says "grant this scope to get it working" and the enumerated version isn't documented anywhere, the wildcard is just faster to copy-paste.

I went back through the config side of sentinel-scan-cli's heuristics (the manifest-only static checks, no live probing) and the wildcard-scope check is one of the simpler ones, and also one of the more consistently useful ones once you start looking for it.

What it actually flags

The rule is narrow on purpose: a tool or server entry declares a scope/permission field that's a wildcard or an unbounded blanket term instead of an enumerated list. Concretely, things like:

{
  "mcpServers": {
    "internal-crm": {
      "command": "npx",
      "args": ["-y", "@example/crm-mcp"],
      "scopes": ["admin:*"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

versus the version that actually says what the tool touches:

{
  "mcpServers": {
    "internal-crm": {
      "command": "npx",
      "args": ["-y", "@example/crm-mcp"],
      "scopes": ["contacts:read", "contacts:write", "notes:read"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Both configs might end up granting the same tool the same effective access if the server only ever calls three CRM endpoints internally. The difference is that the second one tells you, and anyone reviewing the config later, exactly what those three endpoints are. The first one tells you nothing until you read the server's source or wait for something to go wrong.

Why this is worth checking even though it's "just config text"

This is a static manifest check, not a runtime capability audit, so it has an honest limitation: it can't tell you what a wildcard scope actually resolves to at the API level, and it can't catch a server that under-declares its scope but over-reaches in code anyway. What it does catch is the much more common failure, which is nobody bothering to enumerate scopes at all because the wildcard already "works."

The place this bites is usually months later, when a second, unrelated MCP server gets added to the same agent session and now you've got a wildcard-scoped CRM tool sitting next to a tool that reads arbitrary web content. Reviewing "does this pairing make sense" is a lot harder when one side of it is admin:* instead of a short concrete list. Auditing scope creep is basically impossible retroactively if nothing was recorded narrowly in the first place.

The fix is almost always available, just not the default path

Most MCP servers that support scoped permissions at all support enumerated scopes too, the wildcard just tends to be the first example in the README because it's shorter to write. Enumerating takes an extra five minutes of reading the server's tool list and mapping which tools you're actually going to call, and it pays for itself the first time someone else has to review the config without spelunking through the server's source.

If you want to check your own mcp.json files for this pattern (and a handful of related static issues: plaintext remote transports, hardcoded credentials in args, missing provenance metadata on remote-sourced servers) sentinel-scan-cli does this as a pure static scan, no network calls, no server execution. Mapped against the OWASP MCP Top 10 categories in a sample report if you want to see the full output shape before running it.

What's your actual scope granularity looking like in production configs, enumerated by default or wildcard-until-it-breaks?

Top comments (0)