{"record":{"id":"718ab598b4f6d42f","repo":"abhigyanpatwari/GitNexus","slug":"label-contains-an-unsafe-path-component-relati","errorCode":null,"errorMessage":"{label} contains an unsafe path component: {relative}","messagePattern":"(.+?) contains an unsafe path component: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/evolution.py","lineNumber":81,"sourceCode":"\n\ndef _require_real_directory(path: Path, *, label: str) -> None:\n    try:\n        metadata = path.lstat()\n    except OSError as exc:\n        raise ValueError(f\"{label} is unavailable: {path}: {exc}\") from exc\n    if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):\n        raise ValueError(f\"{label} must be a real non-symlink directory: {path}\")\n\n\ndef _require_directory_chain(root: Path, relative: Path, *, label: str) -> None:\n    \"\"\"Validate each lexical directory without erasing links via resolve().\"\"\"\n\n    _require_real_directory(root, label=label)\n    current = root\n    for part in relative.parts:\n        if part in {\"\", \".\", \"..\"}:\n            raise ValueError(f\"{label} contains an unsafe path component: {relative}\")\n        current /= part\n        _require_real_directory(current, label=label)\n\n\ndef _bounded_regular_bytes(path: Path, *, limit: int, label: str) -> bytes:\n    \"\"\"Read one bounded regular file without following its leaf link.\"\"\"\n\n    try:\n        before = path.lstat()\n    except OSError as exc:\n        raise ValueError(f\"{label} is unreadable: {path}: {exc}\") from exc\n    if stat.S_ISLNK(before.st_mode) or not stat.S_ISREG(before.st_mode):\n        raise ValueError(f\"{label} must be a regular non-symlink file: {path}\")\n    if before.st_size > limit:\n        raise ValueError(f\"{label} exceeds the bounded evidence limit\")\n\n    descriptor = os.open(path, os.O_RDONLY | getattr(os, \"O_NOFOLLOW\", 0))\n    try:","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/evolution.py#L63-L99","documentation":"Thrown by _require_directory_chain() in eval/workflow_bench/evolution.py when iterating relative.parts and finding a component that is '', '.', or '..'. These components are rejected outright because they enable path traversal or no-op confusion when constructing paths inside the sandbox, without needing to resolve links.","triggerScenarios":"A candidate overlay file whose path relative to the overlay root contains '..' or '.' or an empty segment — e.g. ../escape.yaml, ./x.yaml, or a//b.yaml. The check fires during candidate_overlay_payload() walking each file's parent chain.","commonSituations":"A hand-crafted or tarball-extracted candidate that includes traversal segments to escape the overlay root; buggy candidate-generation code joining paths with leading '/'; an empty path part from string splitting.","solutions":["Rebuild the overlay so every path is a clean relative path with no '.'/'..'/empty segments.","Audit the candidate generator to normalize paths (PurePosixPath and reject non-normal).","Re-extract tarballs defensively and drop any entry whose relative path has unsafe parts.","Treat this as a security signal if the source is untrusted — investigate provenance."],"exampleFix":"# before\nfiles = ['../secret.yaml', 'skill/x.yaml']\n# ValueError: candidate overlay directory contains an unsafe path component: ../secret.yaml\n\n# after\nfiles = ['skill/x.yaml']  # traversal entries dropped at generation time","handlingStrategy":"validation","validationCode":"from pathlib import PurePosixPath\ndef safe_relative(rel: str) -> PurePosixPath:\n    parts = PurePosixPath(rel).parts\n    if any(c in {'', '.', '..'} for c in parts):\n        raise SystemExit(f'unsafe overlay path component: {rel}')\n    return PurePosixPath(rel)\n# validate every candidate path before passing to candidate_overlay_payload","typeGuard":"def is_unsafe_path_error(exc: ValueError) -> bool:\n    return 'contains an unsafe path component' in str(exc)","tryCatchPattern":"try:\n    candidate_overlay_payload(overlay)\nexcept ValueError as e:\n    if is_unsafe_path_error(e):\n        # drop offending entries, regenerate overlay, retry\n        raise\n    raise","preventionTips":["Normalize candidate paths at generation time and reject any with . or .. parts.","Treat path-traversal entries from untrusted sources as a security signal.","Use PurePosixPath and validate .parts explicitly."],"tags":["workflow-bench","validation","path-traversal","security","sandbox","evolution"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}