T09 · Insecure Skill Coding Practices
- Location
dashboard.js:129- Finding
Shell Command Injection Through Unvalidated Skill Slugs
- Content
View full analysis
Vulnerability Details
File Location:
dashboard.js:129-132,dashboard.js:269-271,dashboard.js:294-296,dev-dashboard.js:100-102,commands/update.js:15-17,commands/update.js:33-35, andcommands/uninstall.js:18-20
Vulnerability Type: OS command injection throughchild_process.exec
Risk Level: HighVulnerable Code
dashboard.js:129-132:js async function checkUpdate(skill) { try { const output = await execCommand(`clawhub inspect ${skill.slug} --json`); const remote = JSON.parse(output);dashboard.js:269-271:js async function executeUpdate(skillSlug) { try { const output = await execCommand(`clawhub update ${skillSlug}`);dashboard.js:294-296:js async function executeUninstall(skillSlug) { try { await execCommand(`clawhub uninstall ${skillSlug}`);dev-dashboard.js:100-102:js async function fetchClawhubData(slug) { try { const output = await execCommand(`clawhub inspect ${slug} --json`);commands/update.js:15-17:js async function checkUpdate(skillSlug) { return new Promise((resolve, reject) => { exec(`clawhub inspect ${skillSlug} --json`, { encoding: 'utf8', timeout: 30000 }, (error, stdout, stderr) => {commands/update.js:33-35:js async function executeUpdate(skillSlug) { return new Promise((resolve, reject) => { exec(`clawhub update ${skillSlug}`, { encoding: 'utf8', timeout: 60000 }, (error, stdout, stderr) => {commands/uninstall.js:18-20:js async function executeUninstall(skillSlug, stateFile) { return new Promise((resolve, reject) => { exec(`clawhub uninstall ${skillSlug}`, { encoding: 'utf8', timeout: 60000 }, (error, stdout, stderr) => {Technical Analysis
The affected functions concatenate a skill slug into a command string passed to Node.js
child_process.exec. This API invokes a command she ...[truncated 2004 chars]- Remediation
View remediation
Remediation Suggestions
-
Replace
child_process.execwithexecFileorspawnand pass each argument separately with shell processing disabled:js const { execFile } = require('child_process'); execFile( 'clawhub', ['inspect', skillSlug, '--json'], { encoding: 'utf8', timeout: 30000 }, callback ); -
Apply validation inside every exported function immediately before execution. For example:
js function validateSkillSlug(value) { if (typeof value !== 'string' || !/^[A-Za-z0-9_-]+$/.test(value)) { throw new Error('Invalid skill slug'); } return value; } -
Do not rely exclusively on validation performed while parsing
clawhub list, because direct callers can bypass that path. -
Reject slugs containing whitespace, shell metacharacters, path separators, control characters, or Unicode look-alike characters.
-
Use a centralized command wrapper that accepts an executable and argument array rather than a complete command string.
-
Add tests covering separators, substitutions, redirects, newlines, and other shell metacharacters.
-
