T09 · Insecure Skill Coding Practices
- Location
scripts/search.js:12- Finding
OS Command Injection Through Search Query
- Content
View full analysis
Vulnerability Details
File Location:
scripts/search.js, lines 12-29
Vulnerability Type: OS command injection through unsafe shell interpolation
Risk Level: HighVulnerable Code
javascript const query = process.argv[2]; if (!query) { console.log('❌ 用法:node search.js "关键词"'); process.exit(1); } const requestBody = { query, edition: 'standard', resource_type_filter: [{ type: 'web', top_k: 10 }], search_recency_filter: 'year', safe_search: false, }; try { const result = execSync( `python3 ~/.openclaw/workspace/skills/baidu-search/scripts/search.py '${JSON.stringify(requestBody)}'`, { encoding: 'utf8', env: { ...process.env }, timeout: 30000 } );Technical Analysis
The search query originates from
process.argv[2]and is inserted intorequestBody. AlthoughJSON.stringify()safely serializes the value as JSON, it does not make the resulting string safe for insertion into a shell command.The serialized request is enclosed in shell single quotes. A single quote supplied as part of the query can terminate this quoted argument. Shell metacharacters following that quote can then introduce an additional command. For example, a query shaped like the following can alter the shell command structure:
text keyword'; attacker_command; #The use of
execSync()with a string causes execution through a shell, making shell parsing and command substitution possible. No validation or shell escaping prevents this behavior.The child process also receives a copy of the complete parent environment through:
javascript env: { ...process.env }Consequently, injected commands execute with access to the Agent process environment, potentially including unrelated API keys and publishing credentials.
Attack Path
- An attacker supplies a crafted article topic or search keyword containing a single quote and shell syntax.
- The ...[truncated 1194 chars]
- Remediation
View remediation
Remediation Suggestions
Eliminate shell interpretation by using
execFileSync()orspawnSync()with a separate argument array:javascript const { execFileSync } = require('child_process'); const os = require('os'); const searchScript = path.join( os.homedir(), '.openclaw', 'workspace', 'skills', 'baidu-search', 'scripts', 'search.py' ); const result = execFileSync( 'python3', [searchScript, JSON.stringify(requestBody)], { encoding: 'utf8', timeout: 30000, env: { PATH: process.env.PATH, BAIDU_API_KEY: process.env.BAIDU_API_KEY, }, } );Additional hardening should include:
- Apply a reasonable maximum length to the query.
- Reject control characters such as null bytes and line breaks when they are unnecessary.
- Pass only the environment variables required by the search dependency.
- Avoid attempting to fix this solely with manual shell escaping; argument-array execution is safer.
- Log failures without including credentials or complete environment data.
