T09 · Insecure Skill Coding Practices
- Location
tools/install_skill.js:12- Finding
OS Command Injection in install_skill
- Content
View full analysis
--workdir ./ const command = `clawhub install ${skillName} --workdir ./`; // Run in current workspace exec(command, { cwd: process.env.OPENCLAW_WORKSPACE || process.cwd() }, (error, stdout, stderr) => { ``` ### Technical Analysis The `skillName` argument is attacker-controlled input obtained directly from `process.argv[2]`. The code checks only that it is non-empty and then interpolates it into a command string passed to `child_process.exec`. Because `exec` invokes the command through a system shell, shell metacharacters contained in `skillName` are interpreted rather than treated as part of a literal ClawHub skill identifier. An input containing separators, substitutions, redirections, or pipelines can therefore append or substitute arbitrary shell commands. For example, a value conceptually shaped like: ```text legitimate-skill; attacker-controlled-command ``` would cause the shell to process both the intended installation command and the injected command. The precise syntax depends on the operating system shell. ### Attack Path 1. An attacker or untrusted caller invokes `install_skill` with a crafted `skill_name`. 2. The tool reads that value from `process.argv[2]`. 3. The value is inserted without escaping or validation into: ```text clawhub install --workdir ./ ``` 4. `child_process.exec` passes the resulting string to a system shell. 5. The shell interprets attacker-provided metacharacters and executes the injected command. 6. The injected process runs with the same operating-system identity, environment, filesystem access, and network per ...[truncated 1015 chars]- Remediation
View remediation
{ if (stdout) process.stdout.write(stdout); if (stderr) process.stderr.write(stderr); process.exit(error ? 1 : 0); } ); ``` 2. Validate `skillName` against the official ClawHub identifier grammar. Prefer a strict allowlist of permitted characters and enforce reasonable length limits. For example, if compatible with the actual ClawHub specification: ```js if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(skillName)) { console.error('ERROR: invalid skill_name'); process.exit(1); } ``` 3. Do not attempt to fix this solely by manually quoting or escaping the argument. Avoiding the shell through structured argument passing is the primary control. 4. Run the installer with the minimum required filesystem and network privileges, and avoid exposing unrelated credentials in its environment. 5. Add regression tests using shell metacharacters such as semicolons, pipes, redirection operators, command substitutions, spaces, and newline characters. Tests should verify that these values are rejected or passed only as literal arguments. ]]>
