T09 · Insecure Skill Coding Practices
- Location
SKILL.md:145- Finding
Shell Command Injection Through Unquoted User-Derived Paths
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 145–163
Vulnerability Type: Shell command injection
Risk Level: HighVulnerable Code
bash find <repo-path> -type f \ -not -path '*/node_modules/*' \ -not -path '*/vendor/*' \ -not -path '*/.git/*' \ -not -path '*/dist/*' \ -not -path '*/build/*' \ -not -path '*/target/*' \ -not -path '*/__pycache__/*' \ -not -path '*/bin/*' \ -not -path '*/obj/*' \ -not -name '*.json' \ -not -name '*.yaml' -not -name '*.yml' \ -not -name '*.md' -not -name '*.txt' -not -name '*.rst' \ -not -name '*.lock' \ -not -name '*.svg' -not -name '*.png' -not -name '*.jpg' \ | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -30The same unsafe interpolation pattern also appears in
references/verification-patterns.md, including lines 33–42 and 94–112:bash rg -l "{basename}" <repo-path> --type-not sql --type-not json --type-not yaml --type-not svg --type-not pngbash rg -l "from ['"]@/${rel_path}['"]" <source-dir>/Technical Analysis
The skill derives
repo-pathfrom the current directory or user-supplied project information and then inserts it into shell command templates without quoting it or separating it safely from command syntax. Other filesystem-derived placeholders, includingsource-dir,basename, andrel_path, are similarly embedded in shell commands and regular expressions without consistent shell and regular-expression escaping.If an Agent implements these templates through literal shell-string substitution, shell metacharacters in an attacker-controlled path can terminate the intended argument and introduce additional commands. Whitespace and glob characters can also change argument boundaries or expand unexpectedly.
Dynamic filenames embedded in
rgexpressions create an additional correctness and safety concern. Regular-expression metacharacters m ...[truncated 1901 chars]- Remediation
View remediation
Remediation Suggestions
-
Treat every repository path, source directory, filename, and relative path as untrusted input.
-
Pass dynamic values as distinct process arguments rather than constructing shell command strings. Prefer an execution API that accepts an argument array and does not invoke a shell.
-
When shell use is unavoidable, quote path variables and terminate option parsing explicitly:
bash find -- "$repo_path" -type f rg -l --fixed-strings -- "$basename" "$repo_path" -
Do not concatenate user-derived paths with shell syntax. Construct derived paths using a safe path API or assign them to variables and quote every expansion:
bash source_path="${source_dir%/}/" rg -l -- "$pattern" "$source_path" -
Use fixed-string searches where regular expressions are unnecessary. Where a regular expression is required, escape dynamic values with a tested regex-escaping function before insertion.
-
Canonicalize the repository path, confirm that it exists and is a directory, and reject control characters or unexpected path forms before running commands.
-
Before deletion, resolve every candidate to a canonical path and verify that it remains beneath the approved repository root.
-
Add explicit guidance forbidding
eval,sh -c, and equivalent execution of dynamically assembled command strings. -
Add tests covering paths and filenames containing spaces, quotes, semicolons, dollar signs, command substitutions, leading hyphens, glob characters, newlines, and regular-expression metacharacters.
-
Apply these protections consistently to all placeholder-based commands in
SKILL.mdandreferences/verification-patterns.md.
-
