T09 · Insecure Skill Coding Practices
- Location
index.js:112- Finding
Shell Command Injection Through Unquoted Workspace Paths
- Content
View full analysis
{ const src = path.join(skillSourcePath, 'assets/templates', `hr_${t}.md`); const dst = path.join(hrWorkspace, `${t.toUpperCase()}.md`); if (fs.existsSync(src)) { execSync(`cp ${src} ${dst}`); } }); const targetSkillPath = path.join(hrWorkspace, 'skills/feishu-team-manager'); execSync(`rm -rf ${targetSkillPath}`); execSync(`mkdir -p ${targetSkillPath}`); execSync(`cp -r ${skillSourcePath}/* ${targetSkillPath}/`); execSync(`openclaw agents add hr_recruiter --workspace ${hrWorkspace}`); ``` The same unsafe pattern occurs during synchronization: ```javascript const hrWorkspace = hrAgent.workspace; if (hrWorkspace && fs.existsSync(hrWorkspace)) { const targetSkillPath = path.join(hrWorkspace, 'skills/feishu-team-manager'); execSync(`cp -r ${skillSourcePath}/* ${targetSkillPath}/`); console.log("Skill files synchronized to the HR workspace."); } ``` ### Technical Analysis The code constructs shell command strings by directly interpolating paths derived from: - The `HOME` environment variable. - The Skill installation path. - The `workspace` property in `openclaw.json`. No shell quoting, escaping, canonicalization, or trust-boundary validation is applied. Node.js `execSync()` invokes a shell, so metacharacters embedded in one of these values are interpreted as shell syntax rather than as part of a filesystem path. The synchronization branch is particularly dangerous because ...[truncated 1293 chars]- Remediation
View remediation
