T09 · Insecure Skill Coding Practices
- Location
scripts/setup.cjs:13- Finding
Shell Command Injection Through Environment-Controlled Workspace Path
- Content
View full analysis
Vulnerability Details
File Location:
scripts/setup.cjs:13, 23-25, 77-84
Vulnerability Type: OS command injection through shell-based argument concatenation
Risk Level: HighVulnerable Code
js const OPENCLAW_DIR = process.env.OPENCLAW_HOME || path.join(os.homedir(), '.openclaw');js function runCommand(args) { try { return { code: 0, output: execSync(args.join(' '), { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], shell: true }) }; } catch (e) { return { code: e.status || 1, output: e.stderr || e.stdout || e.message }; } }js const { code, output } = runCommand([ 'openclaw', 'agents', 'add', agent.id, '--name', `"${agent.name}"`, '--workspace', `"${path.join(TEAM_DIR, agent.id)}"`, '--description', `"${agent.desc}"`, ]);Technical Analysis
OPENCLAW_HOMEis read from the process environment and incorporated into the workspace argument passed torunCommand. The function joins all arguments into one string and executes that string withshell: true.Although the generated workspace path is surrounded by double quotes, shell metacharacters that remain active inside double quotes—particularly command substitutions such as
$(command)and backticks—can still be evaluated by the shell. Consequently, quoting the value this way does not provide a security boundary.The vulnerability is reachable during agent registration because the environment-derived path is included in the command passed to
execSync.Attack Path
- An attacker obtains the ability to influence the environment used to launch
setup.cjs, such as through a wrapper script, CI configuration, compromised shell profile, or manipulated deployment command. - The attacker sets
OPENCLAW_HOMEto a value containing shell command substitution, for example a path containing$(malicious-command). - The setup script constructs the agent registration argumen ...[truncated 960 chars]
- An attacker obtains the ability to influence the environment used to launch
- Remediation
View remediation
Remediation Suggestions
-
Replace shell-based string execution with an API that passes arguments directly to the executable:
js const { execFileSync } = require('child_process'); function runOpenClaw(args) { try { return { code: 0, output: execFileSync('openclaw', args, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], shell: false, }), }; } catch (e) { return { code: e.status || 1, output: e.stderr || e.stdout || e.message, }; } } -
Pass values such as names, descriptions, and workspace paths as individual arguments without adding shell quotes.
-
Avoid generic command helpers that accept preassembled command strings.
-
Validate
OPENCLAW_HOMEas an absolute filesystem path and reject null bytes or other invalid path content as defense in depth. -
When possible, resolve the path with
path.resolveand verify that the resulting directory has the expected owner and location.
-
