feat(mcp): add MCP-029, TypeScript tool writes to the filesystem - #94
feat(mcp): add MCP-029, TypeScript tool writes to the filesystem#94bradAGI wants to merge 1 commit into
Conversation
MCP-005 covers the Python path-safety case; the TypeScript half was missing. Mirrors CSDK-012, including its coarse-signal caveat — it flags any filesystem write rather than only unnormalized paths, because TS path-normalization analysis is not yet wired. Deployment is what sharpens this for MCP. 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.
|
Thanks @bradAGI, this is a careful pair. The rule is schema-clean ( The thing to sort out is the ID. One more note: every shipped rule needs a rationale doc in Happy to take this once the numbering is settled. |
MCP-005 covers the Python path-safety case; the TypeScript half was missing. Mirrors CSDK-012 — the TS half of the Claude SDK pair — including its coarse-signal caveat, stated in the explanation so the finding is honest about itself: it flags any filesystem write, not only unnormalized paths, because TS path-normalization analysis isn't wired yet. Confidence 0.5 to match.
Deployment is what sharpens this for MCP, and it's the part worth having in the finding text. A stdio server is launched as a subprocess by whatever client the user is running, so it inherits that user's own filesystem permissions, not a service account's. A write escaping its intended directory doesn't hit a sandbox — it reaches the user's home directory, dotfiles, and SSH keys.
The second half is that the server cannot see the injection. It receives a well-formed
tools/callfor a path it has no way to distinguish from a legitimate one, so there's no server-side signal to alert on. Containment has to be structural.The fix names the stronger remedy for the common case: derive the filename server-side from an id rather than accepting a path over the protocol at all.
Verification — engine built at
main:Fire (
writeFileSync(notePath, body)withnotePathfrom the tool schema):MCP-029Silent (server-derived id, no caller-supplied path): no findings
No new predicates, so no
schema_versionbump.