Fosowl/agenticSeek · error · PermissionError
Path '{path}' is outside the agent workspace ({base})
Error message
Path '{path}' is outside the agent workspace ({base}) What it means
After resolving the candidate path with os.path.realpath, resolve_workspace_path() checks is_within_directory(resolved, base) and raises PermissionError if the resolved location escapes the workspace directory. This is a sandbox/containment guard: it blocks absolute paths pointing elsewhere and relative paths containing '..' traversal that would resolve outside the agent workspace.
Source
Thrown at sources/workspace.py:90
"""
Resolve a user or model-provided path inside the agent workspace.
Raises:
ValueError: empty path
PermissionError: resolved path escapes the workspace
"""
if path is None or not str(path).strip():
raise ValueError("Empty path")
base = work_dir or get_work_dir()
candidate = str(path).strip()
if os.path.isabs(candidate):
resolved = os.path.realpath(candidate)
else:
resolved = os.path.realpath(os.path.join(base, candidate))
if not is_within_directory(resolved, base):
raise PermissionError(
f"Path '{path}' is outside the agent workspace ({base})"
)
return resolved
View on GitHub (pinned to ae57a23577)
Solutions
- Pass a path relative to the workspace (no leading '/', no '..' escaping it) or a path whose realpath is inside the workspace directory.
- Pass the intended base explicitly via the work_dir parameter so the containment check is evaluated against the correct directory.
- Remove or re-point symlinks inside the workspace that target external locations, since realpath resolves them and trips the check.
- If external access is genuinely needed, copy/sync the resource into the workspace rather than bypassing the check; never weaken is_within_directory.
Example fix
// before
resolved = resolve_workspace_path('/home/dev/data/report.csv')
// after
resolved = resolve_workspace_path('data/report.csv') # relative to workspace Defensive patterns
Strategy: validation
Validate before calling
import os
def path_is_inside_workspace(candidate, base):
base_real = os.path.realpath(base)
cand = str(candidate).strip()
if os.path.isabs(cand):
resolved = os.path.realpath(cand)
else:
resolved = os.path.realpath(os.path.join(base_real, cand))
return os.path.commonpath([resolved, base_real]) == base_real
if not path_is_inside_workspace(user_path, work_dir):
raise PermissionError(f"refusing path outside workspace: {user_path}") Type guard
def is_safe_relative_path(p) -> bool:
s = str(p)
return bool(s.strip()) and not s.startswith('/') and '..' not in os.path.normpath(s).split(os.sep) Try / catch
try:
resolved = resolve_workspace_path(user_path, work_dir)
except PermissionError as e:
logger.warning("workspace escape blocked: %s", e)
raise HTTPException(status_code=400, detail="path must stay within the workspace") from e Prevention
- Store and pass workspace-relative paths, never absolute paths.
- Reject or normalize '..' segments in user-supplied paths before resolution.
- Audit the workspace for symlinks that point outside it; recreate them as copies if needed.
- When the base moves between environments, re-derive paths from the new base instead of persisting absolute ones.
- Keep the containment check intact in code review; treat any bypass as a security regression.
When it happens
Trigger: Calling resolve_workspace_path('/etc/passwd') with an absolute path outside the base; calling it with '../secrets.txt' or 'a/../../etc/hosts' where the realpath lands outside the workspace; a symlink inside the workspace pointing to an external target (realpath follows symlinks); changing work_dir so a previously valid path now resolves outside it.
Common situations: Agents accepting user-supplied file paths (path traversal attempts); symlinks in the workspace created by tools or test fixtures pointing to /tmp or home; environment migration where the workspace base moved but stored paths are absolute; misconfigured work_dir that is narrower than expected so legitimate relative paths escape it.
Related errors
- Model not set
- Ollama connection failed. is the server running ?
- Tool must be a callable object (a method)
- Prompt file not found at path: {file_path}
- Permission denied to read prompt file at path: {file_path}
AI-assisted analysis of Fosowl/agenticSeek@ae57a23577 (2026-08-30).
Data as JSON: /api/errors/37aa46a97a76ed23.
Report an issue: GitHub.