T09 · Insecure Skill Coding Practices
- Location
server.js:163- Finding
Unauthenticated Remote Shell Command Injection
- Content
View full analysis
{ try { const { id } = req.params; const { message } = req.body; if (!message) { return res.status(400).json({ success: false, error: 'Message is required' }); } const agentConfigPath = path.join(CONFIG.agentsDir, id, 'config.json'); let agentConfig = null; try { agentConfig = await readJsonFile(agentConfigPath); } catch (e) {} const agentId = id.replace('agent-', ''); const workspace = agentConfig?.workspace || `workspace-${agentId}`; const workspacePath = path.join(CONFIG.workspaceDir, workspace); try { await fs.access(workspacePath); } catch (e) { return res.status(404).json({ success: false, error: `Agent workspace does not exist: ${workspacePath}` }); } const safeMessage = message.replace(/"/g, '\\"').replace(/\n/g, ' '); const { stdout } = await execCmd( `cd "${workspacePath}" && openclaw agent --agent ${agentId} --message "${safeMessage}" --json 2>&1` ); ``` The command execution helper explicitly enables a shell: ```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 }); }); }); } ``` ### Technical Analysis The request-controlled `message` is interpolated into a command executed by `zsh`. The attempted sanitization only escapes double quotes and replaces newline characters. It does not prevent shell expansion within double quotes, including: - Command substitution using `$(...)` - Command substitution using backticks - Parameter expansion - Other shell-specific substitutio ...[truncated 1448 chars]- Remediation
View remediation
