abhigyanpatwari/GitNexus · critical · ValueError

overlay destination escapes repository: {target}

Error message

overlay destination escapes repository: {target}

What it means

All errors below are raised by internal helpers of `eval/workflow_bench/promotion_apply.py` and propagate to the caller of the public entry points: `apply_promoted_overlay(overlay, repo_root, *, expected_digest, expected_target_bases)`, `destination_base_digests(overlay, repo_root)`, `committed_destination_base_digests(overlay, repo_root, *, ref)` and `freeze_overlay(overlay, destination)`. The module applies promoted skill overlays across the canonical skill tree plus its shipped mirrors (`gitnexus/skills`, `gitnexus-claude-plugin/skills`) in a TOCTOU-hardened, symlink-rejecting, descriptor-bound transaction. `_open_target_parent` rejects a target immediately when `target.is_absolute() or not target.parts or '..' in target.parts`. Targets derive from `mirror_targets(relative)` built off the overlay payload's relative paths (see `candidate_overlay_payload`). Absolute, empty, or `..`-bearing paths would escape the held repository-root descriptor, so they are refused before any directory walk.

Source

Thrown at eval/workflow_bench/promotion_apply.py:193

            stat.S_ISLNK(final.st_mode)
            or not stat.S_ISDIR(opened.st_mode)
            or not stat.S_ISDIR(final.st_mode)
            or final_resolved != root
            or not (identity(metadata) == identity(opened) == identity(final))
        ):
            raise ValueError(f"repository root changed while opening: {root}")
    except OSError as exc:
        os.close(descriptor)
        raise ValueError(f"repository root changed while opening: {root}") from exc
    except BaseException:
        os.close(descriptor)
        raise
    return root, descriptor


def _open_target_parent(root_descriptor: int, target: PurePosixPath) -> int:
    if target.is_absolute() or not target.parts or ".." in target.parts:
        raise ValueError(f"overlay destination escapes repository: {target}")
    flags = os.O_RDONLY | os.O_DIRECTORY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
    current = os.dup(root_descriptor)
    try:
        for part in target.parts[:-1]:
            try:
                metadata = os.stat(part, dir_fd=current, follow_symlinks=False)
            except OSError as exc:
                raise ValueError(f"overlay destination parent is unavailable: {target}") from exc
            if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
                raise ValueError(f"overlay destination parent must not be a symlink: {target}")
            try:
                child = os.open(part, flags, dir_fd=current)
            except OSError as exc:
                raise ValueError(f"overlay destination parent changed while opening: {target}") from exc
            opened = os.fstat(child)
            if (
                opened.st_dev,
                opened.st_ino,

View on GitHub (pinned to d540b00184)

Solutions

  1. Inspect the overlay payload paths: `for r,_ in candidate_overlay_payload(overlay)[1]: print(r)`.
  2. Strip/normalize member names when building the overlay; reject absolute and `..` entries at overlay-authoring time.
  3. Re-create the overlay from a clean source tree using only repo-relative names.

Example fix

// before
# overlay contains an entry like b'../escape/SKILL.md'
apply_promoted_overlay(overlay, repo_root=root)
// after
_, payload = candidate_overlay_payload(overlay)
bad = [str(r) for r,_ in payload if r.is_absolute() or not r.parts or '..' in r.parts]
assert not bad, f'overlay has escaping entries: {bad}'
apply_promoted_overlay(overlay, repo_root=root)
Defensive patterns

Strategy: validation

Validate before calling

def assert_no_escape(payload):
    for rel, _ in payload:
        assert not rel.is_absolute() and rel.parts and '..' not in rel.parts, f'escaping path: {rel}'
_, payload = candidate_overlay_payload(overlay)
assert_no_escape(payload)
apply_promoted_overlay(overlay, repo_root=root)

Type guard

from pathlib import PurePosixPath
def overlay_paths_are_safe(payload) -> bool:
    return all(
        (not r.is_absolute()) and r.parts and ('..' not in r.parts)
        for r, _ in payload
    )

Try / catch

except ValueError as exc:
    if 'escapes repository' in str(exc):
        raise SystemExit(f'refusing overlay with traversal entry: {exc}')

Prevention

When it happens

Trigger: The overlay payload contains an absolute path, an empty relative path, or a path with `..` segments; equivalently the candidate overlay ZIP/tar declared a traversal entry.

Common situations: A hand-crafted or corrupted overlay file includes entries like `/etc/passwd`, `../../sibling`, or a bare empty name; a packaging tool wrote absolute member names.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/f817863b088e6793. Report an issue: GitHub.