T09 · Insecure Skill Coding Practices
- Location
SKILL.md:30- Finding
Shell Command Injection Through Unsafe Template Substitution
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 30–61
Vulnerability Type: Shell command injection
Risk Level: HighThe skill instructs the agent to insert user-controlled company names and domains, as well as externally sourced result IDs, directly into shell commands:
bash node tools/clis/exa.js search --query "[company name] company overview" --num-results 10 --textbash node tools/clis/exa.js search --query "[company name] [domain.com] overview" --num-results 10 --textbash node tools/clis/exa.js search --query "[company name] company overview" --num-results 10 --dry-runbash node tools/clis/exa.js search --query "[company] funding round investment" --num-results 5 --text node tools/clis/exa.js search --query "[company] leadership team executives" --num-results 5 --text node tools/clis/exa.js search --query "[company] product features pricing" --num-results 5 --text node tools/clis/exa.js search --query "[company] news announcement" --num-results 5 --start-date "[30 days ago YYYY-MM-DD]" --textbash node tools/clis/exa.js contents --ids "[id1],[id2],[id3]" --text --highlightsTechnical Analysis
The documented commands interpolate untrusted values into command strings intended for shell execution. Although the placeholders are enclosed in double quotes, shell double quotes do not prevent command substitution using
$()or backticks. An attacker can therefore supply a crafted company name or domain containing shell syntax. Search-result IDs may likewise be unsafe if returned content can influence them.For example, a company name containing
Example $(touch /tmp/exa-injection)would produce:bash node tools/clis/exa.js search --query "Example $(touch /tmp/exa-injection) company overview" --num-results 10 --textIf executed through a shell,
touch /tmp/exa-injectionis evaluated before the Node process starts. Quotation alon ...[truncated 1735 chars]- Remediation
View remediation
Remediation Suggestions
-
Do not create shell command strings by concatenating or substituting user-controlled values.
-
Invoke Node through an argument-array API such as
spawnorexecFilewith shell processing disabled:javascript spawn("node", [ "tools/clis/exa.js", "search", "--query", companyName + " company overview", "--num-results", "10", "--text" ], { shell: false }); -
Update the skill instructions to require structured tool invocation or direct API calls rather than executable shell templates.
-
Validate company domains against a strict domain-name format when a domain is expected.
-
Validate result IDs against the exact identifier format returned by Exa, rejecting shell metacharacters and unexpected delimiters.
-
Treat company names as opaque data and pass them as individual process arguments. Allowlist validation alone should not replace shell-free execution.
-
If shell execution is unavoidable, apply a well-tested, platform-specific shell-escaping library to every dynamic value; do not rely on surrounding values with double quotes.
-
Run the research tool with least privilege, restricted filesystem access, minimal environment variables, and constrained network permissions to reduce impact if validation fails.
-
Add security tests using inputs containing
$(), backticks, quotes, semicolons, newlines, pipes, and redirection operators, verifying that none are interpreted as shell syntax.
-
