T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:94
- Finding
- Path Traversal in MCP Filesystem Integration Example<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:94-103` **Vulnerability Type**: Path traversal enabling unauthorized file access and modification **Risk Level**: High ### Vulnerable Code ```python # MCP Server for file access @server.resource("file://documents/{path}") async def read_document(path: str): with open(f"documents/{path}") as f: return f.read() @server.tool("write_document") async def write_document(path: str, content: str): with open(f"documents/{path}", "w") as f: f.write(content) return {"status": "written"} ``` ### Technical Analysis The filesystem integration directly interpolates an externally supplied `path` into a local filesystem path. It does not reject absolute paths, normalize path components, resolve symbolic links, or verify that the resulting path remains under the intended `documents` directory. An attacker able to invoke these MCP endpoints could supply traversal sequences such as `../.env`, `../../etc/passwd`, or paths targeting application configuration. The operating system resolves the `..` components before opening the file, allowing the request to escape the expected directory. The write operation creates an additional integrity risk because an attacker can overwrite any file writable by the MCP server process. The exact scope depends on the operating-system privileges and working directory of that process. ### Attack Path 1. An operator implements or deploys the documented filesystem MCP server. 2. The attacker gains permission to call the `file://documents/{path}` resource or `write_document` tool. 3. The attacker supplies a crafted path containing traversal components, such as `../.env`. 4. Python passes `documents/../.env` to the operating system without a containment check. 5. The operating system resolves the path outside the intended `documents` directory. 6. The read endpoint returns the targeted file, or the write endpoint modifies it. 7. Information obtained from ...[truncated 796 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Define a fixed, minimally privileged root directory for all document operations. - Reject absolute paths and path components such as `..`. - Resolve both the configured root and requested path to canonical paths, then verify that the requested path remains beneath the root. - Account for symbolic-link traversal by validating the resolved path rather than only checking the original string. - Separate read and write authorization, and expose write access only when required. - Run the MCP server under a dedicated operating-system account with access only to the intended document directory. - Use an allowlist of document identifiers instead of accepting arbitrary filesystem paths where possible. - Add tests covering traversal sequences, absolute paths, alternate separators, URL-encoded traversal, and symbolic links. A hardened implementation should follow this pattern: ```python from pathlib import Path DOCUMENT_ROOT = Path("documents").resolve() def resolve_document_path(path: str) -> Path: requested = Path(path) if requested.is_absolute(): raise ValueError("Absolute paths are not permitted") resolved = (DOCUMENT_ROOT / requested).resolve() if resolved != DOCUMENT_ROOT and DOCUMENT_ROOT not in resolved.parents: raise ValueError("Path escapes the document directory") return resolved @server.resource("file://documents/{path}") async def read_document(path: str): safe_path = resolve_document_path(path) return safe_path.read_text() @server.tool("write_document") async def write_document(path: str, content: str): safe_path = resolve_document_path(path) safe_path.write_text(content) return {"status": "written"} ``` ]]>
