{"record":{"id":"41c80d037553244c","repo":"HKUDS/Vibe-Trading","slug":"path-p-r-escapes-the-workspace-root","errorCode":null,"errorMessage":"Path {p!r} escapes the workspace root","messagePattern":"Path (.+?) escapes the workspace root","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/path_utils.py","lineNumber":73,"sourceCode":"        Absolute resolved path inside `workdir`.\n\n    Raises:\n        ValueError: If `p` uses a UNC share, or its resolved form escapes\n            `workdir`. Callers surface this back to the LLM as a tool error.\n    \"\"\"\n    _rejects_unc(p)\n    base = Path(workdir).resolve()\n    # Expand ~ so home-relative paths (e.g. ~/.vibe-trading/scripts/foo.py)\n    # resolve correctly instead of being treated as literal directory names.\n    expanded = Path(p).expanduser()\n    if expanded.is_absolute():\n        resolved = expanded.resolve()\n    else:\n        resolved = (base / p).resolve()\n    try:\n        resolved.relative_to(base)\n    except ValueError as exc:\n        raise ValueError(f\"Path {p!r} escapes the workspace root\") from exc\n    return resolved\n\n\ndef _agent_root() -> Path:\n    \"\"\"Return the agent package root.\"\"\"\n    return Path(__file__).resolve().parents[2]\n\n\ndef _configured_file_roots() -> list[Path]:\n    \"\"\"Return file roots configured through the environment.\"\"\"\n    raw = get_env_config().api.vibe_trading_allowed_file_roots\n    roots: list[Path] = []\n    for item in raw.split(\",\"):\n        item = item.strip()\n        if not item:\n            continue\n        _rejects_unc(item)\n        roots.append(Path(item).expanduser().resolve())","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/path_utils.py#L55-L91","documentation":"safe_path expands the input, resolves it against the workspace base, and requires the resolved path to stay inside base via Path.relative_to. Anything that resolves outside (absolute path elsewhere, '..' traversal, symlink escaping) raises this error.","triggerScenarios":"Passing '../..' style relative paths, absolute paths outside workdir, or a symlink inside workdir pointing outside that resolves beyond the root.","commonSituations":"Generated code using absolute temp paths, prompts referencing files outside the workspace, or symlinks created by build tooling.","solutions":["Use paths relative to the workspace root without '..' segments","Place needed files inside workdir first","If a file legitimately lives elsewhere, add its directory via the allowed-roots env var instead of bypassing"],"exampleFix":"# before\nsafe_path(\"../../etc/passwd\", workdir)\n# after\nsafe_path(\"data/input.csv\", workdir)","handlingStrategy":"type-guard","validationCode":"from pathlib import Path\ncand = (workdir / file_path).resolve()\nif workdir not in cand.parents and cand != workdir:\n    raise ArgumentError(f\"{file_path} escapes workspace\")","typeGuard":"def stays_inside(p: str, base: Path) -> bool:\n    try:\n        (base / p).resolve().relative_to(base)\n        return True\n    except ValueError:\n        return False","tryCatchPattern":"try:\n    resolved = safe_path(file_path, workdir)\nexcept ValueError as e:\n    if \"escapes the workspace root\" in str(e):\n        file_path = relocate_into(file_path, workdir)","preventionTips":["Prefer bare relative filenames","Reject '..' segments in user-supplied paths","Audit symlinks inside the workspace"],"tags":["path-validation","workspace-containment","security"],"backgroundTag":"path-traversal-rejected","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}