T09 · Insecure Skill Coding Practices
- Location
scripts/ecosystems.py:53- Finding
Arbitrary Shell Command Injection Through User-Controlled Search Queries
- Content
View full analysis
Vulnerability Details
File Location:
scripts/ecosystems.py:53-68
Vulnerability Type: OS command injection through unsafe shell invocation
Risk Level: HighVulnerable Code
python # Build search query from keywords search_terms = " ".join(query.get('keywords', [])) if not search_terms: search_terms = query.get('task', '') if not search_terms: return [] # Execute Skills CLI search cmd = f'npx skills find "{search_terms}" --json' result = subprocess.run( cmd, shell=True, capture_output=True, text=True, timeout=10 )Technical Analysis
The search terms originate from the user's natural-language query and are interpolated directly into a command string. The command is then executed with
shell=True, causing shell metacharacters, command substitutions, and quote characters in the query to be interpreted by the operating-system shell.Quoting
search_termswith double quotes is not sufficient. An attacker can include a closing double quote followed by a shell command. The query is split into keywords byunderstand_user_need()inscripts/skill_finder.py, but that operation does not sanitize shell syntax. The first five attacker-controlled tokens can therefore reach this command construction.The subprocess timeout only limits execution duration; it does not prevent injected commands from reading files, changing files, spawning background processes, or making network requests.
Attack Path
- An attacker supplies a crafted skill-search query containing a closing quote and a shell command, such as tokens structured to produce
" ; id ; echo ". SmartSkillFinder.understand_user_need()converts the query to keyword tokens without removing shell syntax.search_ecosystems()passes those tokens tosearch_skills_cli().search_skills_cli()joins the tokens and inserts them into the command string.- `subprocess.run(..., ...[truncated 734 chars]
- An attacker supplies a crafted skill-search query containing a closing quote and a shell command, such as tokens structured to produce
- Remediation
View remediation
Remediation Suggestions
Eliminate shell interpretation and pass each argument separately:
python result = subprocess.run( ["npx", "--no-install", "skills", "find", search_terms, "--json"], shell=False, capture_output=True, text=True, timeout=10, check=False, )Apply the following additional controls:
- Reject control characters and enforce a reasonable maximum query length.
- Use an allowlisted local executable path rather than relying on shell command resolution.
- Prefer a documented HTTPS API over invoking a package runner.
- Run the search integration with minimal filesystem and network privileges.
- Add regression tests containing quotes, semicolons, command substitutions, newlines, pipes, and redirection operators.
- Ensure all duplicate implementations use the corrected invocation pattern.
