| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
ResourceTemplate.matches() URL-decodes extracted parameters but did not
re-validate that the decoded values still satisfy the [^/]+ segment
constraint. An attacker could send a URI like:
files://..%2F..%2Fetc%2Fpasswd
The encoded %2F passes the regex match on the raw URI, but after
unquote() it becomes ../../etc/passwd — a path traversal payload that
is then passed directly to the template function via fn(**params).
The fix re-checks every decoded parameter value against the original
[^/]+ pattern and returns None (no match) if any value now contains a
forward slash.
|
Closing this as inactive — no maintainer response after 30 days. The security finding and fix remain valid. If this is still relevant, I'm happy to reopen, rebase, or re-submit against a different branch. Just drop a comment. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Vulnerability Summary
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ("Path Traversal")
Severity: High
Affected file: src/mcp/server/mcpserver/resources/templates.py — ResourceTemplate.matches()
Data Flow
Exploit Sketch
Before fix: name = "../../../secrets/api_keys.json" → resolves to /secrets/api_keys.json
After fix: matches() returns None → request is rejected
Fix Description
The fix adds a post-decode validation step in ResourceTemplate.matches(). After URL-decoding extracted parameter values, each value is re-validated against the same [^/]+ segment constraint that was applied to the encoded form. If a decoded value contains a / character (which could only come from an encoded %2F), matches() returns None.
Rationale
Change Details
Test Results Summary
Tested the following scenarios to confirm correctness:
Disprove Analysis
We systematically attempted to disprove this finding across multiple dimensions:
Authentication Check
No authentication on ResourceTemplate.matches() or read_resource. Auth is opt-in via MCPServer(auth=...). Default servers run without auth. The resources/read handler is accessible to any connected MCP client.
Network Check
Default transport is stdio (local process). HTTP transports default to 127.0.0.1 with DNS rebinding protection. However, servers can be configured to bind to 0.0.0.0 or deployed over HTTP — the README shows streamable HTTP examples suggesting production HTTP use is expected.
Caller Trace
matches() is called from exactly one place: ResourceManager.get_resource() → MCPServer.read_resource() → _handle_read_resource(). The URI comes directly from params.uri (client-supplied). Attacker-controlled data reaches this code path.
Prior Validation
Zero validation existed on decoded parameter values before this fix. Pydantic validate_call only enforces type (str), not content.
Existing Mitigations
Similar Code Paths
The low-level server API does not use ResourceTemplate — it delegates to user callbacks directly. This is not a parallel vulnerability because low-level users don't use templates and are responsible for their own parsing. No other instances of template parameter extraction without post-decode validation exist.
Known Limitation
The fix does not block %5C → \ (Windows backslash path separator). On Windows, ..\..\secret is a valid traversal. This is a separate concern given the URI spec uses / exclusively, and could be addressed in a follow-up if desired.
Verdict
Confirmed valid with high confidence. The vulnerability is clearly demonstrable, the fix is correct and minimal, and it addresses the primary attack vector at the single chokepoint for template parameter extraction.
Preconditions for Exploitation
This fix was prepared through a 4-stage review process including vulnerability identification, fix development, testing, and adversarial disprove analysis.