Skills: URI traversal validation skips percent-encoded dot-segments
Mantenedores costumam responder em até 1 dia
@Varshith-Kali já está trabalhando nisso.
Desde 13/10/2026.
- #3703 de @chauvuusvn — fechado sem integrar
Avaliação
- Dificuldade
- 2/5
- Tempo estimado
- 1-3 horas
- Facilidade para iniciantes
- 78/100
Direção de pesquisa
Leia src/mcp/shared/skills.py, com foco em _validate_resource_uri_in_skill() e validate_directory_result(). Comece rastreando como cada função divide e verifica os segmentos do caminho URI e, em seguida, adicione testes de regressão para segmentos de ponto codificados por porcentagem em ambos os caminhos de validação. A tarefa estará concluída quando os segmentos . e .. codificados forem rejeitados, enquanto os URIs de recursos válidos e os filhos diretos continuarem passando.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
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.
- Linguagem predominante
- Python
- Estrelas
- 24.5k
- Forks
- 4k
- Merge médio
- 18h 31min
- PRs com merge (30d)
- 38
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de modelcontextprotocol/python-sdk
-
2026-07-28 SSE responses share one header list, so in-place middleware appends leak across responsesTalvez livre de novo Um pull request para esta issue foi fechado sem ser mesclado. Abertabug spec-2026-07-28 v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
modelcontextprotocol/python-sdk#3701 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
bug v1 v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
modelcontextprotocol/python-sdk#3698 ·
Mantenedores costumam responder em até 1 dia
-
Streamable HTTP: Content-Type handling is order dependent and accepts invalid valuesTalvez já em andamento @jayzuccarelli assumiu há 2 dias. Abertabug v1 v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
modelcontextprotocol/python-sdk#3691 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Type annotation gaps and unhandled FileNotFoundError in src/mcp/cli/cli.pyTalvez livre de novo Um pull request para esta issue foi fechado sem ser mesclado. Abertaenhancement
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 84/100
modelcontextprotocol/python-sdk#3673 · 4 comentários ·
Mantenedores costumam responder em até 1 dia
-
Streamable HTTP server rejects a mixed-case Content-Type with 415Talvez já em andamento @CRYPTONIKAV assumiu há 4 dias. Abertabug v1 v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
modelcontextprotocol/python-sdk#3670 · 4 comentários ·
Mantenedores costumam responder em até 1 dia
Todas as issues de modelcontextprotocol/python-sdk
Issues semelhantes
-
customer-reported question
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
Azure/azure-sdk-for-python#49548 · 1 comentário · 1 reação ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 88/100
btclib-org/btclib-wallet#409 ·
Mantenedores costumam responder em até 1 dia
-
Phase 2 PSA Capability & Career Profile
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
bcgov/digital-journeys#2310 ·
-
bug good first issue
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
fastmachinelearning/hls4ml#1582 ·
Mantenedores costumam responder em até 3 dias
-
Sort modelsAbertaenhancement good first issue
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
Mantenedores costumam responder em até 1 dia