{"record":{"id":"5361a93e011edfd7","repo":"anthropics/skills","slug":"relationship-target-escapes-the-package-target-r-5361a9","errorCode":null,"errorMessage":"relationship target escapes the package: {target!r}","messagePattern":"relationship target escapes the package: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/pptx/scripts/office/helpers/__init__.py","lineNumber":48,"sourceCode":"        return None\n\n    target = urllib.parse.unquote(target)\n\n    if \"\\\\\" in target:\n        raise ValueError(f\"relationship target is not a POSIX part name: {target!r}\")\n\n    if target.startswith(\"/\"):\n        joined = target.lstrip(\"/\")\n    else:\n        joined = posixpath.join(posixpath.dirname(source_part), target)\n\n    parts: list[str] = []\n    for segment in posixpath.normpath(joined).split(\"/\"):\n        if segment in (\"\", \".\"):\n            continue\n        if segment == \"..\":\n            if not parts:\n                raise ValueError(f\"relationship target escapes the package: {target!r}\")\n            parts.pop()\n        else:\n            parts.append(segment)\n\n    if not parts:\n        raise ValueError(f\"relationship target resolves to nothing: {target!r}\")\n    return \"/\".join(parts)\n\n\ndef rels_source_part(rels_file: Path, unpacked_dir: Path) -> str:\n    owner_dir = rels_file.parent.parent.relative_to(unpacked_dir)\n    return posixpath.join(owner_dir.as_posix(), rels_file.name[: -len(\".rels\")]).lstrip(\"./\")\n\n\ndef part_text(data: bytes) -> str:\n    return data.decode(\"utf-8\", \"surrogateescape\")\n\n","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/anthropics/skills/blob/f6656c1256d5a8adfa37db9110046ef20bac644c/skills/pptx/scripts/office/helpers/__init__.py#L30-L66","documentation":"pptx copy of the package-escape guard (same as error 4): opc_target() rejects relationship targets whose normalized path climbs above the package root via '..'. OPC part names cannot address anything outside the package, so such a target is malformed (or a traversal attempt) and resolution aborts.","triggerScenarios":"A relationship in a PPTX .rels file with a target like '../../../../tmp/x' or an over-deep '../../' relative to the owning part; reached via thumbnail.py's slide-list build or clean.py's reference walk.","commonSituations":"Malicious/fuzzed decks with zip-slip-style rels targets; hand-authored .rels with wrong '..' counts relative to the source part; generators emitting absolute-ish traversal prefixes.","solutions":["Fix the target to stay inside the package — prefer a package-absolute target starting with '/' (e.g. '/ppt/media/image1.png').","Remember relative targets resolve from the owning part's directory (e.g. ppt/slides/_rels → one '..' reaches ppt/).","For untrusted input, quarantine: this shape often signals an attack, not an accident.","Regenerate the deck with a conformant tool."],"exampleFix":"<!-- before: ppt/_rels/presentation.xml.rels -->\n<Relationship Id=\"rId9\" Type=\".../slideMaster\" Target=\"../../../../ppt/slideMasters/slideMaster1.xml\"/>\n\n<!-- after -->\n<Relationship Id=\"rId9\" Type=\".../slideMaster\" Target=\"/ppt/slideMasters/slideMaster1.xml\"/>","handlingStrategy":"validation","validationCode":"import posixpath\n\ndef target_stays_in_package(target: str, source_part: str) -> bool:\n    if not target or target.startswith(\"/\"):\n        return True\n    joined = posixpath.normpath(posixpath.join(posixpath.dirname(source_part), target))\n    return not joined.startswith(\"..\") and \"/..\" not in joined","typeGuard":null,"tryCatchPattern":"try:\n    opc_target(target, source_part, target_mode)\nexcept ValueError as e:\n    if \"escapes the package\" in str(e):\n        log.security(\"traversal rel target %r in %s — skipping\", target, source_part)\n        skip_relationship()\n    else:\n        raise","preventionTips":["Use package-absolute targets (leading '/') in generated .rels.","Treat escape targets in untrusted decks as hostile.","Validate packages with an OOXML validator before pipelines run."],"tags":["pptx","ooxml","opc","security","path-traversal"],"backgroundTag":null,"analyzedSha":"f6656c1256d5a8adfa37db9110046ef20bac644c","analyzedAt":"2026-08-14T16:09:17.493Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}