fix(skills): replace string prefix check with strict path containment

This commit is contained in:
Ruzzgar 2026-04-10 18:05:30 +03:00 committed by Teknium
parent 0943e2a272
commit 313a8c6833
2 changed files with 19 additions and 1 deletions

View file

@ -1846,6 +1846,23 @@ class TestOptionalSkillSourceBinaryAssets:
assert bundle.files["assets/neutts-cli/samples/jo.txt"] == b"hello\n"
assert "assets/neutts-cli/src/neutts_cli/__pycache__/cli.cpython-312.pyc" not in bundle.files
def test_fetch_rejects_sibling_directory_traversal(self, tmp_path):
optional_root = tmp_path / "optional-skills"
sibling_skill_dir = tmp_path / "optional-skills-escape" / "pwned"
optional_root.mkdir()
sibling_skill_dir.mkdir(parents=True)
(sibling_skill_dir / "SKILL.md").write_text(
"---\nname: pwned\ndescription: traversal\n---\n\nBody\n",
encoding="utf-8",
)
src = OptionalSkillSource()
src._optional_dir = optional_root
bundle = src.fetch("official/../optional-skills-escape/pwned")
assert bundle is None
class TestQuarantineBundleBinaryAssets:
def test_quarantine_bundle_writes_binary_files(self, tmp_path):

View file

@ -3028,7 +3028,8 @@ class OptionalSkillSource(SkillSource):
# Guard against path traversal (e.g. "official/../../etc")
try:
resolved = skill_dir.resolve()
if not str(resolved).startswith(str(self._optional_dir.resolve())):
optional_root = self._optional_dir.resolve()
if not resolved.is_relative_to(optional_root):
return None
except (OSError, ValueError):
return None