T09 · Insecure Skill Coding Practices
- Location
install.cjs:111- Finding
Shell Command Injection Through User-Controlled Search and Skill Names
- Content
View full analysis
Vulnerability Details
File Location:
install.cjs, lines 111, 184, and 225
Vulnerability Type: OS command injection
Risk Level: HighVulnerable Code
javascript const output = execSync(`npx clawhub search ${query} 2>&1`, { encoding: 'utf-8', cwd: SKILLS_DIR });javascript execSync(`unzip -q "${zipPath}" -d "${extractDir}"`, { stdio: 'inherit' });javascript execSync(`npx clawhub install ${skillName} --force`, { encoding: 'utf-8', cwd: SKILLS_DIR, stdio: 'inherit' });Technical Analysis
queryandskillNameare derived directly from command-line arguments. They are interpolated into command strings passed toexecSync, which invokes a system shell.Shell metacharacters, command substitutions, redirections, or embedded quotation marks contained in these arguments are interpreted by the shell rather than treated solely as literal data. Quoting
zipPathandextractDirdoes not provide sufficient protection because a malicious skill name can contain a quotation mark that terminates the quoted argument.The vulnerable search and installation fallback commands become reachable when the corresponding API operation fails. The
unzipinvocation is reached after a skill archive has been downloaded.Attack Path
- An attacker causes the tool to be invoked with a crafted search query or skill name containing shell syntax.
- For the search or installation fallback, the attacker causes or waits for the ClawHub API operation to fail.
- The crafted value is inserted into an
execSynccommand string. - The operating-system shell parses the injected syntax.
- The attacker's command executes with the privileges of the user running the installer.
For the extraction command, a crafted skill name can influence
zipPathandextractDir; embedded shell quoting or substitution syntax can escape the intended arguments whenunzipis invok ...[truncated 462 chars]- Remediation
View remediation
Remediation Suggestions
-
Replace shell-based
execSynccalls withexecFileSyncorspawnSync, passing arguments as an array:javascript execFileSync('npx', ['clawhub', 'search', query], { encoding: 'utf8', cwd: SKILLS_DIR, stdio: 'inherit', shell: false }); execFileSync('unzip', ['-q', zipPath, '-d', extractDir], { stdio: 'inherit', shell: false }); execFileSync('npx', ['clawhub', 'install', skillName, '--force'], { cwd: SKILLS_DIR, stdio: 'inherit', shell: false }); -
Validate skill names with a restrictive allowlist, such as
^[A-Za-z0-9._-]+$. -
Reject path separators, control characters, shell metacharacters, and names beginning with an option prefix.
-
Avoid invoking
npxin a way that can download packages dynamically. Resolve and execute a trusted, pinned CLI binary instead. -
Add tests covering semicolons, command substitutions, quotation marks, newlines, redirections, and option-injection payloads.
-
