MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy
← Threat Catalog

Server Implementation

Path traversal in tool arguments

HIGHAIVSS 7.8CWE: CWE-22OWASP: LLM02Agentic: T03Rule: MCP-003

A file-reading or file-writing tool joins a user-supplied filename to a base directory without normalizing, letting `../` segments escape the intended scope. Scoped to tool-argument flows; the equivalent bug at the `resources/read` primitive is covered by MCP-212.

What it is

Path traversal is the bug where `base_dir + "/" + user_input` produces a path outside `base_dir` because `user_input` contains `../` or an absolute path. The canonical attack reads `/etc/passwd` or `~/.ssh/id_rsa`. On Windows, `..` and drive prefixes like `C:` play the same role.

Why it matters for MCP

File-system tools are one of the most common MCP server types — "let the model read my notes folder." Authors remember to scope reads to a base directory but forget that `os.path.join("/notes", user_arg)` is not a security check. An LLM instructed by a malicious note will happily try `../../../etc/shadow`; on misconfigured containers, the file exists and is readable.

Vulnerable example

example.py
1
BASE = "/srv/notes"
2
3
@server.tool()
4
def read_note(filename: str) -> str:
5
    path = os.path.join(BASE, filename)
6
    with open(path) as f:
7
        return f.read()

Secure example

example.py
1
from pathlib import Path
2
BASE = Path("/srv/notes").resolve()
3
4
@server.tool()
5
def read_note(filename: str) -> str:
6
    # Reject absolute paths and any ".." segment before resolution.
7
    candidate = (BASE / filename).resolve()
8
    if BASE not in candidate.parents and candidate != BASE:
9
        raise ValueError("path outside notes directory")
10
    return candidate.read_text()

How MCPSafe detects this

We flag file I/O where the argument has not passed through a path-normalization + containment check (`resolve()` + `is_relative_to`, `path.resolve()` + `startsWith(base)`, or equivalent). `open(user_arg)` with no preprocessing is always flagged.

See the full threat catalog for every documented detection.

Framework alignment

OWASP LLM Top-10 (2025)
LLM02 — Sensitive Information Disclosure
OWASP Agentic AI Top-10
T03 — Privilege Compromise
AIVSS v0.5
7.8 (HIGH)AIVSS:1.0/S:HIGH/AV:N/AU:L/BR:M/CD:I

Illustrative CVEs

CVEs of the same CWE class. Not MCP-specific, but exemplify the failure mode MCPSafe detects.

  • CVE-2024-23334 — aiohttp path traversal — MCP servers that use aiohttp inherit this class

Further reading

  • CWE-22: Path Traversal
  • OWASP Path Traversal

Scan an MCP server for this issue

MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.

Scan now