There is now enough of a public record on MCP filesystem security to stop guessing and start reading. I went through it. The cases are more similar to each other than I expected, and the pattern is worth naming.
The record so far
EscapeRoute — Anthropic's own Filesystem MCP Server. Two CVEs, both in every version before npm 2025.7.1. Found 30 March 2025, patched 1 July 2025.
CVE-2025-53110 (CVSS 7.3) is a directory containment bypass. The server checked whether a requested path started with an approved directory. If /private/tmp/allow_dir was approved, then /private/tmp/allow_dir_sensitive_credentials also passed — different directory, same prefix. List, read and write outside the boundary.
CVE-2025-53109 (CVSS 8.4) is worse. Symlink validation checked the parent directory of the link rather than what the link actually pointed at. Chain it with the first bug and you get arbitrary reads and writes — /etc/sudoers was the published example — and code execution through macOS Launch Agents.
CVE-2026-40576 — excel-mcp-server, versions up to 0.1.7, CVSS 9.4, published 21 April 2026. Path traversal. get_excel_path() neither validated absolute paths nor resolved ../ sequences. In SSE or HTTP transport mode that meant unauthenticated arbitrary file read, write and overwrite. Fixed in 0.1.8.
DuneSlide — CVE-2026-50548 and 50549, CVSS 9.8, in Cursor's terminal sandbox: working-directory parameter validation plus symlink canonicalisation failures.
And the aggregate numbers, for scale. Endor Labs analysed 2,614 MCP implementations and found 82% use file operations prone to path traversal. OX Security's April 2026 scan found 7,000 MCP servers reachable from the open internet. By July 2026 there were 14 CVEs assigned to MCP implementations.
The thing they have in common
Read the root causes next to each other:
- a path that starts with the allowed string
- a symlink whose parent is inside the boundary
- a path with
../that was never resolved before the check - a working directory parameter that was validated but not canonicalised
In each case the boundary existed. It was checked. The check ran and returned "allowed". The boundary was a comparison between two pieces of text, and the attack was to produce text that passed the comparison while pointing somewhere else.
This is not a new class of bug. Path traversal is older than most people reading this. What is new is where it sits: between a language model and a filesystem, in a component that was added precisely to be the safety layer.
Why "grant a directory" makes this worse than it needs to be
The dominant model is: hand the server one or more directory paths, everything under them is fair game. That design has two properties that turn a path bug into a bad day.
The unit is large. A project directory is thousands of files. If the boundary fails, everything inside is exposed at once — plus, in the EscapeRoute case, whatever the symlink pointed at.
The default is allow. Inside the granted tree, permission is implicit. Nothing has to be decided for a file to be readable; it just has to be in there. So the correctness of the entire arrangement rests on one string comparison being right, every time, for every input anyone can construct.
A per-file model does not magically fix path resolution. Any implementation that turns a request into a file on disk can get that wrong, mine included. What changes is what a mistake costs. If every file carries its own level and the default is deny, a path that slips through the check still has to land on something that was explicitly granted. The blast radius of a resolution bug is the difference between "one file the user had already opened up" and "the tree, and anything a symlink in it points to".
That is a smaller claim than "we are secure". It is the honest one.
What this does not solve
Worth stating, because half the posts on this topic stop before this part:
- It does not prevent path-resolution bugs. It bounds them.
- It does nothing about data you did grant. If a file is readable and the assistant can also send mail or make requests, that file can leave. Grant narrowly.
- It does not cover other doors. A second filesystem connector, or a shell tool, is not governed by a layer it never passes through.
- It is not a substitute for patching. Every CVE above was fixed. Update your servers.
The practical read
If you run an MCP filesystem server today, three things are worth an afternoon:
-
Check your versions against the CVEs above. The Anthropic one is fixed in
2025.7.1; excel-mcp-server in0.1.8. -
Find out whether your boundary is a string comparison or a resolution. If the code does
path.startsWith(allowedDir)anywhere, you have the EscapeRoute bug class in your stack, patched or not. -
Look at what is actually inside your granted directories. Most people grant a project folder and forget that it contains
.env,.git, credentials, client data, and an SSH key or two.
The third one costs nothing and is usually the most alarming.
Disclosure: I build Kobel, a desktop permission gateway for Windows and macOS that applies per-file levels instead of directory grants — which is why I read this record closely, and why the "what this does not solve" section above is not a formality. Its documentation, including the full permission model and its limits, is public at github.com/Kobel123/kobel-mcp.
Sources: Cymulate on EscapeRoute (CVE-2025-53109 / 53110) · SentinelOne on CVE-2026-40576 · The Agent Report: MCP security landscape 2026 · Embrace The Red on the Anthropic filesystem bypass · The Vulnerable MCP Project
Top comments (0)