T09 · Insecure Skill Coding Practices
- Location
SKILL.md:36- Finding
Shell Command Injection in Documented Integration
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 36-41
Vulnerability Type: Shell command injection through unsafe argument concatenation
Risk Level: HighVulnerable Code
javascript // After LLM call completes const usage = result.usage; exec('node /path/to/track-usage.js track <job-name> ' + usage.input_tokens + ' ' + usage.output_tokens + ' ' + model);Technical Analysis
The documented integration constructs a shell command by concatenating runtime values and passes the resulting string to
exec(). Becauseexec()invokes a shell, shell metacharacters contained inmodel, token values, or a dynamically substituted job name can alter the intended command.No quoting, allowlist validation, or shell escaping is applied. If an upstream API response, configuration source, plugin, or other attacker-influenced input controls one of these values, payloads containing separators or command substitutions could cause an additional operating-system command to execute.
The implementation in
track-usage.jsdoes not itself launch subprocesses; the vulnerability exists in the integration pattern explicitly recommended by the skill documentation.Attack Path
- A user integrates the skill using the documented
exec()example. - An attacker gains influence over
modelor another value concatenated into the command, such as through a compromised or attacker-controlled upstream response. - The attacker supplies a value containing shell syntax that terminates or extends the intended command.
- The application concatenates that value into the command string without validation or escaping.
exec()submits the complete string to the system shell.- The shell interprets the injected syntax and executes attacker-selected commands with the privileges of the OpenClaw or cron-job process.
Impact Assessment
Successful exploitation provides arbitrary command execution under the account running the integrating proce ...[truncated 460 chars]
- A user integrates the skill using the documented
- Remediation
View remediation
Remediation Suggestions
Avoid invoking a shell. Use
execFile()orspawn()with an argument array so runtime values are passed as literal arguments:javascript const { execFile } = require('child_process'); execFile('node', [ '/path/to/track-usage.js', 'track', jobName, String(usage.input_tokens), String(usage.output_tokens), model ], (error, stdout, stderr) => { if (error) { console.error('Usage tracking failed:', error); return; } console.log(stdout); });Apply defense-in-depth validation before execution:
- Require token counts to be finite, non-negative integers within reasonable upper bounds.
- Restrict job names to a documented safe format, such as
/^[A-Za-z0-9._-]{1,100}$/. - Validate model identifiers against an allowlist or a narrowly defined format.
- Reject control characters and unexpected input rather than attempting ad hoc shell escaping.
- Use an absolute, trusted Node.js executable path when the runtime environment permits.
- Update
SKILL.mdso users are not instructed to concatenate untrusted values into shell commands.
