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 a relative relationship target against the source part and rejects targets whose normalized path climbs above the package root ('..' more times than there are path segments). OPC part names are package-absolute; escaping the root means the target is malformed and any resolution would be arbitrary. Present in both docx and pptx copies of office/helpers/__init__.py.

Source

Thrown at skills/docx/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

  1. Open the .rels file named in your processing log and fix the Target so it stays inside the package (e.g. '../media/image1.png' from ppt/slides/_rels/, not '../../../../media/image1.png').
  2. Remember relative targets resolve against the RELATIONSHIP FILE'S owner part directory, not the package root — use a leading '/' for package-absolute targets.
  3. If the input is untrusted, treat this error as a security signal and quarantine the file rather than repairing it.
  4. Regenerate the package with a conformant tool (PowerPoint, python-pptx, openpyxl).

Example fix

<!-- before -->
<Relationship Id="rId1" Type=".../slide" Target="../../../../slides/slide1.xml"/>

<!-- after: package-absolute target -->
<Relationship Id="rId1" Type=".../slide" Target="/ppt/slides/slide1.xml"/>
Defensive patterns

Strategy: validation

Validate before calling

import posixpath

def target_stays_in_package(target: str, source_part: str) -> bool:
    if not target or target.startswith("/"):
        return True  # absolute targets cannot escape via '..'
    joined = posixpath.normpath(posixpath.join(posixpath.dirname(source_part), target))
    return not joined.startswith("..") and "/.." not in joined

Try / catch

try:
    opc_target(target, source_part, target_mode)
except ValueError as e:
    if "escapes the package" in str(e):
        log.security("traversal target rejected: %r from %s", target, source_part)
        skip_relationship()  # never auto-repair untrusted traversal targets
    else:
        raise

Prevention

When it happens

Trigger: A relationship like Target="../../../../etc/passwd" or "../../outside.xml" attached to a part near the root (e.g. source_part='_rels/.rels' with heavy '../' traversal); also '..' as the very first segment of an absolute-style target after normpath.

Common situations: Zip-slip-style traversal attempts in malicious or fuzzed OOXML files; hand-built .rels files where the author counted directory levels wrong; converters that emit '../../' prefixes relative to the wrong base part.

Related errors


AI-assisted analysis of anthropics/skills@f6656c1256 (2026-08-14). Data as JSON: /api/errors/b8767cd981a518a6. Report an issue: GitHub.