datawhalechina/hello-agents · error · PatchApplyError
Path escapes repo_root: {rel_path}
Error message
Path escapes repo_root: {rel_path} What it means
Raised by _safe_path when (repo_root / rel_path).resolve() falls outside repo_root after symlink resolution — the classic path-traversal defense. It fires even though the raw string is relative, because components like '../' (or a symlinked directory pointing outside) resolve to a target not under repo_root. Note the check compares string prefixes with os.sep appended, which also rejects a sibling directory whose name starts with repo_root's name.
Source
Thrown at Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py:204
"""
验证路径安全性,防止路径遍历攻击 (Path Traversal)。
确保目标路径在 repo_root 目录下,防止访问仓库外的文件。
参数:
rel_path: 相对路径字符串
返回:
Path: 安全的绝对路径对象
异常:
PatchApplyError: 当路径是绝对路径、包含特殊字符或试图访问仓库外时抛出
"""
if rel_path.startswith("/") or rel_path.startswith("~"):
raise PatchApplyError(f"Absolute paths are not allowed: {rel_path}")
target = (self.repo_root / rel_path).resolve()
# 检查解析后的路径是否以 repo_root 开头
if not str(target).startswith(str(self.repo_root.resolve()) + os.sep) and target != self.repo_root.resolve():
raise PatchApplyError(f"Path escapes repo_root: {rel_path}")
if target.exists() and target.is_symlink():
raise PatchApplyError(f"Refusing to modify symlink: {rel_path}")
return target
def _enforce_suffix(self, target: Path) -> None:
"""
检查目标文件的后缀是否在允许的列表中。
防止意外修改二进制文件、配置文件或其他敏感文件。
参数:
target: 目标文件路径对象
异常:
PatchApplyError: 当文件后缀不在允许列表中时抛出
"""
if target.suffix and target.suffix not in self.allowed_write_suffixes:
raise PatchApplyError(f"Disallowed file suffix for write: {target.suffix}")
View on GitHub (pinned to 606a07d341)
Solutions
- Rewrite the patch path to a clean repo-relative path with no '..' components.
- Ensure repo_root is passed to the executor as a fully resolved absolute path (Path(...).resolve()).
- If a symlink inside the repo must be traversed, replace it with the real location inside repo_root or move the dependency into the repo.
- Pre-validate rel_path with posixpath normalization and reject '..' before invoking apply.
Example fix
# before
rel_path = '../../shared/lib.py' # escapes repo_root
# after
import posixpath
rel_path = posixpath.normpath(rel_path)
assert not rel_path.startswith('..'), 'path escapes repo'
# use 'shared/lib.py' copied into the repo instead Defensive patterns
Strategy: validation
Validate before calling
import posixpath
def safe_rel(rel_path: str) -> str:
if rel_path.startswith(('/', '~')):
raise ValueError('absolute path')
norm = posixpath.normpath(rel_path)
if norm.startswith('..') or posixpath.isabs(norm):
raise ValueError(f'escapes repo_root: {rel_path}')
return norm Type guard
def stays_in_repo(rel_path: str, repo_root: Path) -> bool:
target = (repo_root / rel_path).resolve()
root = repo_root.resolve()
return target == root or str(target).startswith(str(root) + os.sep) Try / catch
try:
executor.apply(patch)
except PatchApplyError as e:
if 'escapes repo_root' in str(e):
raise PermissionError(f'rejected traversal attempt: {e}') # do not retry
raise Prevention
- Pass repo_root as an already-resolved absolute Path.
- Normalize and reject '..' components before building patches.
- Treat this error as a security signal, never as a retryable failure.
When it happens
Trigger: rel_path containing '../' sequences (e.g. '../../etc/cron.d/x'), a path that resolves to repo_root itself being rejected only when it equals neither condition, or a symlink inside the repo pointing to an external directory that resolve() follows.
Common situations: LLM patches copying '../../../' paths from stack traces; repos containing convenience symlinks to shared code outside the repo; repo_root passed as a non-canonical path (e.g. './proj' vs '/abs/proj') so prefix comparison behaves unexpectedly.
Related errors
- Absolute paths are not allowed: {rel_path}
- Refusing to modify symlink: {rel_path}
- Unknown op kind: {kind}
- Disallowed file suffix for write: {target.suffix}
- Patch must start with '*** Begin Patch'
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/7694f3222d569122.
Report an issue: GitHub.