T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- agentar_cli.mjs:851
- Finding
- Workspace Name Path Traversal Enables Writes Outside the Intended Agent Directory<![CDATA[ ## Vulnerability Details **File Location**: `agentar_cli.mjs:851-875` **Vulnerability Type**: Path traversal and arbitrary filesystem write **Risk Level**: High ### Complete Code Snippet ```js } else { const name = agentName || slug.replace(/[^a-zA-Z0-9_-]/g, "-"); const workspaceDir = path.join(WORKSPACES_DIR, name); mkdirp(workspaceDir); const openclawBin = findOpenclawBin(); if (openclawBin) { const result = spawnOpenclawSync(openclawBin, [ "agents", "add", name, "--workspace", workspaceDir, "--non-interactive", ], { encoding: "utf-8", stdio: "pipe" }); if (result.status !== 0 && !(result.stderr || "").includes("already exists")) { rmrf(tmpDir); console.error(`Error: failed to create agent "${name}": ${result.stderr || result.error?.message || "unknown error"}`); process.exit(1); } } else { console.log(" Warning: openclaw CLI not found, skipping agent registration"); } extractWorkspaceFiles(contentDir, workspaceDir); mergeSkills(path.join(contentDir, "skills"), path.join(workspaceDir, "skills")); targetWorkspace = workspaceDir; } ``` ### Technical Analysis The value supplied through `--name` is used directly as a path component. Unlike the marketplace slug, the agent name is not constrained by an identifier validation function. A value containing `../` components can therefore cause the normalized workspace path to escape `WORKSPACES_DIR`. The resulting path is passed to `mkdirp`, `extractWorkspaceFiles`, and `mergeSkills`. These operations create directories, copy files, and remove existing destination directories before replacing them. Consequently, this is not limited to creating an empty directory: content from a remotely downloaded agent archive can be written to an attacker-selected location. ### Attack Path 1. An attacker persuades a user or automation system to install an agentar with a crafted name, such as: ```text --name ../../target-directory ``` 2. The CL ...[truncated 878 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Apply the same strict identifier policy to agent names as to slugs, for example: ```js if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(name)) { throw new Error("Invalid agent name"); } ``` - Resolve and verify the destination before any filesystem operation: ```js const root = path.resolve(WORKSPACES_DIR); const workspaceDir = path.resolve(root, name); const relative = path.relative(root, workspaceDir); if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) { throw new Error("Agent workspace escapes the permitted root"); } ``` - Canonicalize existing parent directories with `fs.realpathSync` and reject symlink-based escapes. - Reject path separators, `.` and `..` components, absolute paths, drive prefixes, and UNC paths. - Perform extraction into a staging directory and move it into place only after all validation succeeds. ]]>
