Here is the state of play in mid-2026: a February scan counted over 8,000 Model Context Protocol servers reachable on the public internet. BlueRock analysed ~7,000 of them and found 36.7% were potentially vulnerable to SSRF. Trend Micro found 492 with zero authentication and zero transport encryption. Akamai went looking at the MCP servers for popular databases and concluded that the baseline security spec they assumed must exist… doesn't.
That is not a mature ecosystem. That is a greenfield with the topsoil already turned over for you.
And the cheapest way to find bugs in it is not fuzzing. It's reading the patch.
The play: one fix, three variants
The single highest-ROI move in MCP-server hunting right now is patch-diff variant analysis. The recipe:
- Find an MCP server that just shipped a security fix.
- Read the fix commit. Identify the exact guard the maintainer added.
- Grep the codebase for sibling sinks that didn't get the guard.
- Validate, dedup, report.
This is the same play Anthropic's team ran on Firefox — read a known memory-safety fix, find the unpatched neighbour of the same shape — just at single-commit scale instead of whole-codebase scale. You don't have their compute. You don't need it. A maintainer who fixes one sink has handed you a labelled training example for free.
The reason it works on MCP servers specifically is that these codebases are young, symmetric, and copy-pasted. Young: the security review hasn't happened yet. Symmetric: where there's a download, there's an upload; where there's a Confluence client, there's a Jira client; where there's a git_show, there's a git_log. Copy-pasted: the same registerClient SSRF sink lives verbatim in a dozen forks.
Worked example: the direction nobody guards
Take CVE-2026-27825 (published, patched) in mcp-atlassian. The confluence_download_attachment MCP tool accepted a download_path parameter and wrote to it with no directory-boundary enforcement — a clean arbitrary-file-write that escalates to RCE (drop a cron entry, wait one scheduler cycle). The fix added a validate_safe_path() guard.
Good fix. Now here's where the variant hunter's brain should fire three questions before the maintainer's coffee is cold:
- The opposite direction. They guarded the write path. What about the read path — the upload_attachment tool that takes a server-side file_path and reads it? An MCP tool that reads an attacker-named local file and ships it somewhere the attacker can see is the read-side mirror of the same bug. When a fix only covers one direction, the other direction is the first place to look.
- The sibling client. mcp-atlassian has both a Confluence and a Jira attachment client. A guard added to one is a guard not added to the other until proven otherwise.
- The unwrapped library function. The MCP tool is a thin wrapper. Does the underlying library function carry the same flaw for any other caller?
I'm not going to hand you a live unpatched finding here — coordinated disclosure exists for a reason, and at least one of those questions is sitting in a vendor's triage queue as I write this. But the method is the point: a path-traversal fix on a write sink is a to-do list, not a closed ticket.
The 2026 MCP variant catalogue (all public, all patch-diffable)
Every one of these is a root-cause pattern you can carry to the next server:
| Root cause | Public anchor CVE | The variant question |
|---|---|---|
| Unvalidated param → SQL construction | CVE-2025-66335 (Apache Doris MCP, SQLi via unchecked db_name) | Which of the other tool params skip validation before hitting the query builder? |
| STDIO transport command pass-through | OX Security's systemic MCP advisory (variants across Python/TS/Java/Rust) | Does this server expose stdio_config.command/args? Is the validator actually called, or just defined? |
| Command-injection hardening bypass | Upsonic CVE-2026-30625, Flowise GHSA-c9gw-hvqq-f33r | The allow-list only permits python/npm/npx — can you smuggle args through the allowed binary? |
| Path-restriction that doesn't restrict | Cyata's CVE-2025-68145 (Git MCP --repository bypass) | Does the boundary check resolve symlinks / expand env vars before validating, or after? |
| "Read-only" tool with a write primitive | CVE-2025-68144 (git_diff used to overwrite files) | Which nominally-read-only tool touches the filesystem as a side effect? |
| Metadata-derived fetch → SSRF | MCP SDK OAuth-discovery SSRF (class-level, forked widely) | Does the server fetch any URL it learned from an untrusted MCP response, with no private-IP guard? |
The OX finding deserves a special note for variant hunters: they found a validator that existed but wasn't wired in. I've seen the same shape this month — a ValidateStdioConfig function sitting in utils/security.go, fully implemented, called from nowhere. Dead-code guards are a goldmine: grep for the validator's name, and if the only hits are its definition and its unit test, the door's open. (In that particular case the transport was also hard-disabled at three other layers, so it was a dud — which is the other half of the discipline: a dead validator is a lead, not a finding.)
How to actually run it as a solo hunter
The mechanics that keep this productive instead of a rabbit hole:
- Pull the fix commit, not just the advisory. git log -p the patched file. The advisory tells you what; the diff tells you the exact guard to hunt the absence of.
- Grep for the guard, not the bug. If the fix added validate_safe_path(, your hunt is grep -L "validate_safe_path" $(grep -rl "open(" src/). You're looking for sinks the guard doesn't protect.
- IP-pin every test. When you validate against a live host, pin the request to the in-scope IP (curl --resolve host:443:<ip>). Never let DNS drift you out of scope. This matters more than it sounds — it's the difference between a clean PoC and an out-of-scope incident.
- Check the dup queue before you draft. On huntr, browse the repo's disclosed bounties — the internal Duplicate/Self-Closed queue is invisible to NVD/GHSA/Patchstack dedup. The number of "novel" findings that are actually three-deep in someone's triage queue will surprise you.
- Run the gate. Before writing a single line of report: is the impact real right now, not theoretical? Is there a working PoC? Is it a duplicate? If the honest answer to "can an attacker do this today" is "only if they already have a foothold," you have a defence-in-depth note, not a submission.
The honest part: what this pays
Read the room before you quit your job. The MCP variant wave is mostly MEDIUM-severity — CVSS 5 to 8. The prompt-injection threat model (which underpins a lot of these) gets pushback from triagers who consider an obedient-LLM a user problem, so lead your impact section with the network-reachable scenario, not the "malicious page tricks the assistant" one. Disclosure outcomes are a coin-flip on the vendor: Apache shipped a CVE for the Doris flaw within the cycle; Alibaba flatly declined to patch the RDS MCP bug. GHSA-channel vendors (the responsible ones) ack within their SLA; some never reply at all.
And the thing the press won't tell you: AI makes the finding cheap and the weaponising expensive. Anthropic's Firefox campaign burned ~$4,000 in API credits to turn found bugs into two working exploits. For MCP servers you rarely need a weaponised exploit — a reachable PoC is enough — but the same asymmetry applies to your time. Finding the variant is an afternoon. Writing the report that survives triage is the actual work.
The takeaway
You are hunting in an ecosystem where 8,000 servers are exposed, a third are SSRF-bait, validators are defined-but-not-called, and the same three sinks repeat across every fork. The maintainers are shipping fixes that cover one direction of one sink. Your job is to read those fixes and ask the question they didn't: what's the mirror?
Patch the write, and the read is still open. That's not a metaphor. That's a methodology.
Hunt responsibly. Pin your scope, run the gate, and let the vendor patch before you publish.
No comments yet