T09 · Insecure Skill Coding Practices
- Location
scripts/create_agent.py:17- Finding
Path Traversal Enables Recursive Deletion Outside the Intended Agent Workspace
- Content
View full analysis
Path: """Lấy đường dẫn workspace của agent""" workspace_name = agent_name.lower().replace(" ", "-") return WORKSPACE_ROOT / f"workspace-{workspace_name}" ``` The generated path is later passed directly to recursive deletion: ```python def delete_agent(agent_name: str) -> Dict[str, Any]: """Xóa agent""" # 1. Xóa workspace workspace = get_agent_workspace(agent_name) if workspace.exists(): shutil.rmtree(workspace) ``` ### Technical Analysis The caller-controlled `agent_name` is transformed only by lowercasing it and replacing spaces with hyphens. Directory separators and `..` traversal components remain valid. The fixed `workspace-` prefix does not provide containment. For example, an input containing multiple traversal components can produce a path resembling: ```text ~/.openclaw/workspace/workspace-../../../target ``` After filesystem path resolution, this may refer to a directory outside the intended agent workspace. The application does not call `resolve()` and does not verify that the resolved target remains beneath `WORKSPACE_ROOT`. The resulting path is passed to `shutil.rmtree()`, which recursively deletes the target directory and its contents. ### Attack Path 1. An attacker or untrusted caller gains the ability to invoke the `delete` action with a chosen agent name. 2. The attacker supplies an agent name containing enough `../` components to escape the intended workspace. 3. `get_agent_workspace()` incorporates those components into the filesystem path. 4. If the resolved directory exists, `delete_agent()` passes it to `shutil.rmtree()`. 5. The selected directory and all accessible cont ...[truncated 765 chars]- Remediation
View remediation
None: if not AGENT_NAME_PATTERN.fullmatch(agent_name): raise ValueError("Invalid agent name") ``` 2. Resolve the generated path and enforce containment before creating or deleting it: ```python def get_agent_workspace(agent_name: str) -> Path: validate_agent_name(agent_name) root = WORKSPACE_ROOT.resolve() target = (root / f"workspace-{agent_name.lower()}").resolve() if target.parent != root: raise ValueError("Agent workspace escapes the workspace root") return target ``` 3. Before recursive deletion, require an application-owned marker file inside the target directory. 4. Reject names containing `/`, `\`, `.`, `..`, null bytes, or platform-specific path separators. 5. Refuse to delete `WORKSPACE_ROOT`, its ancestors, symbolic links, or paths not registered as agent workspaces. 6. Run the Skill under a minimally privileged account and maintain backups of persistent agent data. ]]>
