[Paper] Unsafe by Flow: Uncovering Bidirectional Data-Flow Risks in MCP Ecosystem
Source: arXiv - 2605.07836v1
Overview
Model Context Protocols (MCPs) are the glue that lets large‑language‑model (LLM) agents call external tools—think “search the web”, “run a shell command”, or “query a database”. While they enable powerful workflows, they also open a hidden attack surface: data can flow into a tool in a malicious way, and results can flow out of a tool back to the LLM or host system in an unsafe way. The paper Unsafe by Flow introduces MCP‑BiFlow, a static analysis framework that automatically discovers these bidirectional data‑flow bugs across real‑world MCP servers.
Key Contributions
- Bidirectional taint model that simultaneously tracks request‑side (input) and response‑side (output) data propagation through MCP handlers.
- MCP‑aware entry‑point recovery to locate the diverse registration and dispatch patterns used by MCP servers (e.g., decorators, dynamic routing tables).
- Interprocedural propagation engine that respects MCP‑specific semantics (e.g., “tool‑output is exposed to the LLM” vs. “internal log is private”).
- Comprehensive evaluation on a curated benchmark (32 known MCP bugs) achieving 93.8 % recall, and a large‑scale scan of >15 k open‑source MCP servers uncovering 118 confirmed vulnerability paths.
- Open‑source prototype (MCP‑BiFlow) and a curated dataset of MCP vulnerability cases for the community.
Methodology
- Entry‑point extraction – The analyzer first scans a repository for MCP registration code (e.g.,
register_tool,@mcp_handler). Because developers can register handlers in many ways (static tables, runtime reflection, plugin loading), MCP‑BiFlow builds a control‑flow graph that captures all possible entry points. - Protocol‑specific taint semantics – The authors define two taint sources:
- Requester‑controlled inputs (JSON payloads, command strings).
- Sensitive internal data (environment variables, credentials).
And two sinks: - Sensitive operations (file writes, OS exec).
- MCP‑visible outputs (responses sent back to the LLM).
The analysis tags each variable with a direction (in/out) and propagates the tags through assignments, function calls, and data‑structure manipulations.
- Interprocedural data‑flow analysis – Using a worklist algorithm, the tool follows the taint across function boundaries, handling common Python idioms (decorators, async/await, dynamic imports). It also models the tool‑scoped execution path: a request travels from the dispatcher → handler → internal libraries → response generation.
- Candidate clustering – To keep the output manageable, similar taint paths are merged into “clusters” based on shared source‑sink patterns, then presented to a human reviewer for validation.
Results & Findings
| Evaluation | Metric | Value |
|---|---|---|
| Benchmark (32 known bugs) | Recall | 30 / 32 (93.8 %) |
| Benchmark | Precision (manual check) | ~85 % (few false positives) |
| Real‑world scan (15 452 repos) | Candidate clusters | 549 (after overlap compression) |
| Manual validation | Confirmed vulnerable paths | 118 (in 87 distinct servers) |
| Comparison tools (CodeQL, Semgrep, Snyk Code, MCPScan) | Best recall | ≤ 55 % (none detected the bidirectional flows) |
What it means:
- Existing static analyzers miss the majority of MCP‑related bugs because they look at only one direction of data flow.
- Unsafe propagation is common: roughly 0.7 % of scanned MCP servers contain at least one exploitable bidirectional flow.
- The bidirectional model is essential; many bugs only appear when a request‑side taint reaches a sensitive operation and the resulting output is later fed back into the LLM.
Practical Implications
- For LLM‑tool developers: Integrate MCP‑BiFlow (or similar bidirectional taint checks) into CI pipelines to catch unsafe argument handling and overly permissive response serialization before deployment.
- For platform operators (e.g., LangChain, AutoGPT ecosystems): Adopt the protocol‑aware entry‑point discovery to automatically audit third‑party tool plugins, reducing supply‑chain risk.
- For security teams: The clustering output gives a concise “attack surface map” of each MCP server, making manual triage feasible even for large codebases.
- For API designers: The paper highlights the need for explicit data‑flow contracts (e.g., marking fields as “private” vs. “exposed”) that static tools can consume, encouraging safer MCP specifications.
- Performance impact: MCP‑BiFlow runs as a static analysis step; the authors report analysis times under 2 minutes for typical 5 k‑line Python projects, making it practical for nightly builds.
Limitations & Future Work
- Language scope: The prototype targets Python MCP servers; extending to other languages (Node.js, Go) will require additional entry‑point heuristics.
- Dynamic dispatch: Extremely dynamic registration (e.g., constructing handlers from user‑provided code strings) can evade static recovery, leading to missed paths.
- False positives: While precision is high, some flagged paths involve benign data (e.g., logging of user input) that does not constitute a real exploit. Future work could incorporate runtime profiling to filter these.
- Runtime semantics: The analysis does not model actual LLM reasoning; a malicious model could amplify a benign flow into an exploit. Combining static taint with sandboxed execution traces is a promising direction.
Authors
- Xinyi Hou
- Yanjie Zhao
- Haoyu Wang
Paper Information
- arXiv ID: 2605.07836v1
- Categories: cs.SE
- Published: May 8, 2026
- PDF: Download PDF