T09 · Insecure Skill Coding Practices
- Location
SKILL.md:78- Finding
Shell Command Injection in Documented Search Integration
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 78-83
Vulnerability Type: OS command injection through unsafe shell command construction
Risk Level: HighVulnerable Code:
javascript const { execSync } = require('child_process'); function baiduSearch(query, count = 5) { const scriptPath = '/Users/mac/.openclaw/workspace/skills/baidu-search/baidusearch.js'; const cmd = `node "${scriptPath}" "${query}" -n ${count}`; const output = execSync(cmd, { encoding: 'utf-8' });Technical Analysis
The documented integration places
queryandcountdirectly into a command string passed toexecSync. By default,execSyncexecutes the string through a system shell. Quotation marks aroundquerydo not provide adequate protection because an attacker can include another quotation mark followed by shell metacharacters.For example, a query such as:
text "; id; #can terminate the intended quoted argument and append another command. The resulting command would be structurally similar to:
sh node "/path/to/baidusearch.js" ""; id; #" -n 5The
countargument is also interpolated without validation and can become another injection vector if an attacker can control it.The directly executable
baidusearch.jsimplementation does not contain this flaw because Commander reads arguments fromprocess.argv. The vulnerability is specifically present in the integration pattern recommended bySKILL.md.Attack Path
- An application or Agent adopts the documented
baiduSearchwrapper. - The attacker submits a crafted search query, or an untrusted value reaches the
countparameter. - The wrapper interpolates that value into
cmdwithout shell escaping or strict validation. execSyncpasses the constructed string to the operating-system shell.- The shell interprets the injected metacharacters and executes attacker-supplied commands.
- The inj ...[truncated 717 chars]
- An application or Agent adopts the documented
- Remediation
View remediation
Remediation Suggestions
Do not construct a shell command from user-controlled values. Invoke Node.js directly with an argument array by using
execFileSync,spawn, orspawnSyncwith shell execution disabled:javascript const { execFileSync } = require('child_process'); function baiduSearch(query, count = 5) { const scriptPath = '/Users/mac/.openclaw/workspace/skills/baidu-search/baidusearch.js'; if (typeof query !== 'string' || query.length === 0 || query.length > 500) { throw new TypeError('query must be a non-empty string of at most 500 characters'); } if (!Number.isInteger(count) || count < 1 || count > 100) { throw new RangeError('count must be an integer between 1 and 100'); } return execFileSync( process.execPath, [scriptPath, query, '-n', String(count)], { encoding: 'utf8', timeout: 30000, shell: false } ); }Additional hardening should include:
- Apply strict type, length, and range validation to all arguments.
- Set a finite execution timeout and output-size limit.
- Run the integration under a least-privileged operating-system account.
- Avoid attempting to solve the issue with custom shell escaping when argument-array APIs are available.
- Add automated tests containing quotation marks, semicolons, command substitutions, newlines, and other shell metacharacters.
