anthropics/skills · error · ValueError
relationship target escapes the package: {target!r}
Error message
relationship target escapes the package: {target!r} What it means
opc_target() resolves relationship targets against the source part and rejects any that walk above the package root: when a '..' segment pops an empty segment stack, the target escapes the OPC package. This guards against both malformed files and deliberate ../.. path traversal inside .rels.
Source
Thrown at skills/xlsx/scripts/office/helpers/__init__.py:48
return None
target = urllib.parse.unquote(target)
if "\\" in target:
raise ValueError(f"relationship target is not a POSIX part name: {target!r}")
if target.startswith("/"):
joined = target.lstrip("/")
else:
joined = posixpath.join(posixpath.dirname(source_part), target)
parts: list[str] = []
for segment in posixpath.normpath(joined).split("/"):
if segment in ("", "."):
continue
if segment == "..":
if not parts:
raise ValueError(f"relationship target escapes the package: {target!r}")
parts.pop()
else:
parts.append(segment)
if not parts:
raise ValueError(f"relationship target resolves to nothing: {target!r}")
return "/".join(parts)
def rels_source_part(rels_file: Path, unpacked_dir: Path) -> str:
owner_dir = rels_file.parent.parent.relative_to(unpacked_dir)
return posixpath.join(owner_dir.as_posix(), rels_file.name[: -len(".rels")]).lstrip("./")
def part_text(data: bytes) -> str:
return data.decode("utf-8", "surrogateescape")
View on GitHub (pinned to f6656c1256)
Solutions
- Unzip the file and inspect the Target values in the .rels named in the error — anything starting with ../ chains is the culprit
- Discard files from untrusted sources that trigger this; it is a traversal red flag, not something to patch around
- If you generate packages, compute targets with posixpath.relpath against the correct source part and assert they stay under the root
Defensive patterns
Strategy: try-catch
Validate before calling
import posixpath
def target_stays_in_package(target: str, source_part: str) -> bool:
if target.startswith("/"):
joined = target.lstrip("/")
else:
joined = posixpath.join(posixpath.dirname(source_part), target)
depth = 0
for seg in posixpath.normpath(joined).split("/"):
if seg in ("", "."):
continue
depth = depth - 1 if seg == ".." else depth + 1
if depth < 0:
return False
return True Try / catch
try:
part = opc_target(target, source_part, mode)
except ValueError as e:
if "escapes the package" in str(e):
raise SuspiciousDocument(source_part, target) from e # quarantine, don't sanitize
raise Prevention
- Treat traversal in .rels as a security signal: quarantine the file, never rewrite-and-load silently
- When generating packages, assert resolved targets start with the package root before writing
- Run untrusted Office files through this validator in a sandboxed pipeline step
When it happens
Trigger: Loading a package whose .rels has Target="../../../../etc/passwd" or any target that, resolved relative to the source part (e.g. xl/worksheets + ../..), leaves the package root; also absolute-looking targets that normalize to a parent traversal.
Common situations: Malicious or corrupt Office files (zip-slip via relationships); documents generated by buggy writers computing relative paths from the wrong base; merging .rels from different packages without recomputing targets.
Related errors
- relationship target escapes the package: {target!r}
- relationship target escapes the package: {target!r}
- relationship target is not a POSIX part name: {target!r}
- relationship target resolves to nothing: {target!r}
- {word} not found (not an unpacked .docx?)
AI-assisted analysis of anthropics/skills@f6656c1256 (2026-08-14).
Data as JSON: /api/errors/781286c0d58e6154.
Report an issue: GitHub.