T09 · Insecure Skill Coding Practices
- Location
scripts/idiom.sh:3- Finding
Unquoted User Input Permits Word Splitting and Pathname Expansion
- Content
View full analysis
/dev/null || true; INPUT="$*" python3 -c ' import sys,hashlib cmd=sys.argv[1] if len(sys.argv)>1 else "help" inp=" ".join(sys.argv[2:]) # ... ' "$CMD" $INPUT ``` ### Technical Analysis The script combines all remaining arguments into `INPUT` and later expands `$INPUT` without double quotes. Bash consequently performs word splitting and pathname expansion on the value before invoking Python. This processing occurs even when a caller originally quoted a wildcard. For example, an argument supplied as the literal `'*'` can be expanded by line 31 into filenames from the script's current working directory. The resulting filenames are passed to Python as search terms. If no idiom matches, the Python code includes the reconstructed input in its response: ```python if not found: print(" No match for: {}. Try a Chinese character or English keyword.".format(key)) ``` Shell metacharacters introduced through the variable are not reparsed as shell syntax, so this is not direct command injection. However, unintended wildcard expansion and argument splitting can expose local filenames and alter command behavior. ### Attack Path 1. An attacker causes the skill to execute an idiom search with a literal wildcard, such as `idiom.sh search '*'`. 2. The invoking shell preserves the wildcard because it is quoted. 3. The script stores the wildcard in `INPUT`. 4. The unquoted `$INPUT` expansion on line 31 performs pathname expansion in the script's working directory. 5. Matching local filenames are passed to Python as individual arguments. 6. Python joins those arguments and may display the filenames in the “No match” output. ### Impact Assessment Successful exploitation can disclose names of files and directories visible from the process's current working dire ...[truncated 402 chars]- Remediation
View remediation
/dev/null || true python3 -c ' import sys cmd = sys.argv[1] if len(sys.argv) > 1 else "help" inp = " ".join(sys.argv[2:]) # ... ' "$CMD" "$@" ``` Additional hardening measures: 1. Do not serialize arguments through `INPUT="$*"` when the original argument boundaries can be retained. 2. Double-quote every shell variable expansion unless word splitting or glob expansion is explicitly required. 3. Run ShellCheck in continuous integration and treat findings such as SC2086 as failures. 4. Add tests using literal inputs such as `*`, `?`, whitespace, filenames beginning with `-`, and empty arguments. ]]>
