Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions mcp/path_safety.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,35 @@ rules:
fix: >
Resolve the path with `Path(...).resolve()` and assert it sits under an
allowed root before any I/O touches it. Reject paths that escape the root.

- id: MCP-029
title: TypeScript MCP tool writes to the filesystem
severity: low
confidence: 0.5
language: typescript
applies_to:
- mcp_tool
scope: tool
match:
has_write_call: true
explanation: >
This TypeScript MCP tool handler writes to the filesystem. If the path or
the contents derive from the tool's arguments, the caller on the other
side of the protocol chooses both — and that caller is a model, steerable
by a prompt injection carried in retrieved content or an earlier tool
result. How the server is deployed makes this sharper than it looks: a
stdio server is launched as a subprocess by whatever client the user is
running, so it inherits that user's own filesystem permissions rather
than a service account's, and a write escaping its intended directory
reaches the user's home directory, dotfiles, and SSH keys. The server also
cannot see the injection — it receives a well-formed tools/call for a path
it has no way to distinguish from a legitimate one. (Coarse signal — it
flags any filesystem write, not only unnormalized paths, because
TypeScript path-normalization analysis is not yet wired. Confirm the path
is genuinely caller-supplied before acting.)
fix: >
Confine writes to a dedicated working directory: resolve the final path,
verify it stays under that root before writing, and reject absolute paths
and any input containing "..". Where the tool only ever writes generated
names, derive the filename server-side from an id rather than accepting a
path over the protocol at all.