Skills: URI traversal validation skips percent-encoded dot-segments
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 78/100
Piste de recherche
Lis src/mcp/shared/skills.py, en te concentrant sur _validate_resource_uri_in_skill() et validate_directory_result(). Commence par suivre la façon dont chaque fonction découpe et vérifie les segments du chemin URI, puis ajoute des tests de régression pour les segments point encodés en pourcentage dans les deux chemins de validation. Le travail est terminé lorsque les segments . et .. encodés sont rejetés, tandis que les URI de ressources valides et les enfants directs sont toujours acceptés.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Initial Checks
- I confirm that I'm using the newest release of my line (the latest 2.x, or the latest 1.x if I'm still on v1)
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Release line
2.x (current stable)
Description
In src/mcp/shared/skills.py (added in #3485 for the SEP-2640 Skills extension), _validate_resource_uri_in_skill() and validate_directory_result() check for directory traversal segments against the raw URI path segments:
# src/mcp/shared/skills.py (line 253)
if any(segment in (".", "..") for segment in resource_parts.path.split("/")):
raise ValueError(f"resource URI {resource_uri!r} contains a traversal segment")
Because URI paths are not URL-unquoted prior to validation, percent-encoded traversal segments (e.g. %2e%2e, %2E%2E, or %2e) bypass this check.
Specifically:
- In
_validate_resource_uri_in_skill(), a resource URI such asskill://acme/billing/refunds/%2e%2e/other/secret.txtstarts withroot + "/"(/billing/refunds/), but its segments (["", "billing", "refunds", "%2e%2e", "other", "secret.txt"]) do not literally equal".."or".". As a result, the resource is admitted as a valid member ofskill://acme/billing/refunds/SKILL.md. - In
validate_directory_result(), line 293 checksrelative in (".", ".."). A child URI containing%2e%2eor%2ebypasses this check and is admitted as a valid direct child.
Example Code
from mcp.shared.skills import Skill, SkillResource, ReadDirectoryResult, validate_directory_result
from mcp_types import Resource
root = "skill://git-workflow/SKILL.md"
digest = "sha256:" + "a" * 64
# 1. Percent-encoded traversal bypasses manifest validation:
s = Skill(
uri=root,
frontmatter={"name": "git-workflow", "description": "d"},
resources=[
SkillResource(uri=root, digest=digest, size=10),
SkillResource(uri="skill://git-workflow/%2e%2e/evil.md", digest=digest, size=10)
]
)
# Expected: ValueError / ValidationError for traversal segment
# Observed: Accepted without error
# 2. Percent-encoded dot-segment bypasses directory validation:
res = ReadDirectoryResult(resources=[Resource(uri="skill://pdf/templates/%2e%2e", name="x")])
validate_directory_result("skill://pdf/templates", res)
# Expected: ValueError ("is not a direct child")
# Observed: Accepted without error
Proposed Fix
Normalize path segments with urllib.parse.unquote() before splitting and inspecting dot-segments in both _validate_resource_uri_in_skill and validate_directory_result.
I have a minimal regression test and fix ready and would be happy to submit a PR if this looks good.
- Langage dominant
- Python
- Étoiles
- 24.5k
- Forks
- 4k
- Merge moyen
- 18 h 31 min
- PR mergées (30 j)
- 38
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de modelcontextprotocol/python-sdk
-
Streamable HTTP: Content-Type handling is order dependent and accepts invalid valuesPeut-être pris @jayzuccarelli l’a pris il y a 1 jour. Ouvertebug v1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
modelcontextprotocol/python-sdk#3691 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Type annotation gaps and unhandled FileNotFoundError in src/mcp/cli/cli.pyPeut-être à nouveau libre Une pull request pour cette issue a été fermée sans être fusionnée. Ouverteenhancement
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
modelcontextprotocol/python-sdk#3673 · 4 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Streamable HTTP server rejects a mixed-case Content-Type with 415Peut-être pris @CRYPTONIKAV l’a pris il y a 3 jours. Ouvertebug v1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
modelcontextprotocol/python-sdk#3670 · 4 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Audio(data=b"") raises "Either path or data can be provided", while Image(data=b"") worksPeut-être pris @ajay206 l’a pris il y a 1 jour. Ouvertebug v1 v2
Difficulté 1/5 Moins d'une heure Accessibilité débutants 85/100
modelcontextprotocol/python-sdk#3656 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
enhancement
Difficulté 2/5 1-3 heures Accessibilité débutants 66/100
modelcontextprotocol/python-sdk#3655 ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de modelcontextprotocol/python-sdk
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
-
Difficulté 1/5 Moins d'une heure Accessibilité débutants 62/100
-
Difficulté 1/5 Moins d'une heure Accessibilité débutants 70/100
-
bug
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
topoteretes/cognee#5773 ·
Les mainteneurs répondent en général sous 1 jour
-
MiKTeX: a failed build reports no errors because texify --quiet switches the log to file:line: styleOuverte
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
SublimeText/LaTeXTools#1718 ·