T09 · Insecure Skill Coding Practices
- Location
- server.js:173
- Finding
- Shell Command Injection in Agent Chat and Deletion Endpoints<![CDATA[ ## Vulnerability Details **File Location**: `server.js:29-34`, `server.js:173-201`, `server.js:264-278`; duplicated in `server-gemini.js:25-30`, `server-gemini.js:109-117`, and `server-gemini.js:140-150` **Vulnerability Type**: OS command injection through user-controlled shell command construction **Risk Level**: Critical ### Vulnerable Code ```javascript async function execCmd(cmd) { return new Promise((resolve, reject) => { exec(cmd, { shell: 'zsh' }, (error, stdout, stderr) => { if (error) reject(error); else resolve({ stdout, stderr }); }); }); } ``` ```javascript const agentId = id.replace('agent-', ''); const workspace = agentConfig?.workspace || `workspace-${agentId}`; const workspacePath = path.join(CONFIG.workspaceDir, workspace); // Check whether the workspace exists try { await fs.access(workspacePath); } catch (e) { return res.status(404).json({ success: false, error: `Agent 工作区不存在:${workspacePath}` }); } const safeMessage = message.replace(/"/g, '\\"').replace(/\n/g, ' '); const { stdout } = await execCmd( `cd "${workspacePath}" && openclaw agent --agent ${agentId} --message "${safeMessage}" --json 2>&1` ); ``` ```javascript app.delete('/api/agents/:id', async (req, res) => { try { const { id } = req.params; const agentDir = path.join(CONFIG.agentsDir, id); try { await fs.access(agentDir); } catch (e) { return res.status(404).json({ success: false, error: 'Agent 不存在' }); } await execCmd(`rm -rf "${agentDir}"`); ``` ### Technical Analysis The application constructs Zsh command strings containing request-controlled Agent IDs, workspace values, and chat messages. Replacing double quotes and newlines is not valid shell escaping. Shell expressions such as command substitution remain active inside double quotes, while `agentId` is inserted without shell quoting. The deletion endpoint similarly passes a request-derived path to `rm -rf` through a shell. Path ...[truncated 1171 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Remove the generic `execCmd` shell-string interface. - Invoke `openclaw` through `execFile` or `spawn` with an explicit argument array and `shell: false`. - Set the workspace through the subprocess `cwd` option rather than executing `cd`. - Restrict Agent IDs to a narrow allowlist such as `^[a-z0-9-]+$`. - Validate workspace identifiers separately and enforce canonical path containment. - Replace shell-based `rm -rf` with `fs.rm(path, { recursive: true })`, but only after canonical containment validation. - Run the server under a dedicated, minimally privileged operating-system account. - Add authentication and authorization before exposing any command-executing endpoint. ]]>
