{"record":{"id":"044de6ed9b7a55e5","repo":"langchain-ai/deepagents","slug":"media-path-escapes-outbound-root-path","errorCode":null,"errorMessage":"media path escapes outbound root: {path}","messagePattern":"media path escapes outbound root: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/talon/deepagents_talon/media.py","lineNumber":234,"sourceCode":"        require_relative\n        and (path.is_absolute() or windows_path.is_absolute() or is_windows_drive_path)\n    ):\n        msg = f\"media path must be a local relative path under the outbound root: {path}\"\n        raise ValueError(msg)\n    if \"..\" in path.parts or \"..\" in windows_path.parts:\n        msg = f\"media path must not contain parent-directory traversal: {path}\"\n        raise ValueError(msg)\n\n    root_resolved = root.expanduser().resolve()\n    candidate_input = root_resolved / path if not path.is_absolute() else path\n    try:\n        candidate = candidate_input.resolve(strict=True)\n    except OSError as exc:\n        msg = f\"media file is unavailable: {path}\"\n        raise ValueError(msg) from exc\n    if not candidate.is_relative_to(root_resolved):\n        msg = f\"media path escapes outbound root: {path}\"\n        raise ValueError(msg)\n    if not candidate.is_file():\n        msg = f\"media path is not a regular file: {path}\"\n        raise ValueError(msg)\n    return candidate\n\n\ndef _document_parts(paths: list[Path]) -> list[str]:\n    parts: list[str] = []\n    for path in paths:\n        if path.suffix.lower() not in READABLE_DOCUMENT_EXTENSIONS:\n            parts.append(f\"_(Received unsupported document attachment: {path.name}.)_\")\n            continue\n        try:\n            if path.stat().st_size > MAX_TEXT_DOCUMENT_BYTES:\n                parts.append(f\"_(Document attachment is too large to read inline: {path.name}.)_\")\n                continue\n            content = path.read_text(encoding=\"utf-8\", errors=\"replace\")\n        except OSError:","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/talon/deepagents_talon/media.py#L216-L252","documentation":"ValueError raised by resolve_bounded_media_path when the strictly-resolved real path of the file is not contained within the resolved outbound root. This catches symlink escapes: the file itself may exist, but resolving symlinks leads outside the root.","triggerScenarios":"A symlink inside the outbound root pointing to /etc/passwd or any file outside root; hardlinked or symlinked directories resolving outward.","commonSituations":"Symlinking shared assets into the outbound folder for convenience; CI artifacts that are symlinks into a cache directory; container volume setups with linked paths.","solutions":["Copy the file into the outbound root instead of symlinking it","Point the symlink target inside the outbound root","If intentional, adjust the root to the common ancestor containing the real file"],"exampleFix":"// before\nln -s /var/data/shared.png $OUTBOUND_ROOT/shared.png  # symlink escapes root\n// after\ncp /var/data/shared.png $OUTBOUND_ROOT/shared.png  # real file inside root","handlingStrategy":"validation","validationCode":"root_resolved = root.expanduser().resolve()\ntry:\n    candidate = (root_resolved / relative).resolve(strict=True)\nexcept OSError:\n    candidate = None\nif candidate is None or not candidate.is_relative_to(root_resolved):\n    raise ValueError(f\"path escapes root: {relative}\")","typeGuard":"def stays_within_root(p: Path, root: Path) -> bool:\n    try:\n        return p.expanduser().resolve(strict=True).is_relative_to(root.expanduser().resolve())\n    except OSError:\n        return False","tryCatchPattern":"try:\n    resolved = resolve_bounded_media_path(path, root)\nexcept ValueError as exc:\n    logger.warning(\"Media escapes outbound root: %s\", exc)\n    return None","preventionTips":["Copy files into the outbound root instead of symlinking","Audit outbound directories for symlinks before send","If symlinks are required, ensure targets resolve inside the root (or widen root to the common ancestor)"],"tags":["media","path","security","symlink"],"backgroundTag":"path-traversal","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}