T09 · Insecure Skill Coding Practices
- Location
scripts/script.sh:103- Finding
Arbitrary Command Execution Through Unquoted Directory Argument in the stats Command
- Content
View full analysis
Vulnerability Details
File Location:
scripts/script.sh, lines 103-107
Vulnerability Type: Shell argument injection into afindexpression
Risk Level: HighVulnerable Code
bash cmd_stats() { local dir="${2:-}" [ -z "$dir" ] && die "Usage: $SCRIPT_NAME stats <dir>" echo 'Files:'; find ${2:-.} -type f -name '*.py' -o -name '*.js' -o -name '*.sh' | wc -l; echo 'Lines:'; find ${2:-.} -type f \( -name '*.py' -o -name '*.js' -o -name '*.sh' \) -exec cat {} + 2>/dev/null | wc -l }Technical Analysis
The user-controlled value
${2:-.}is expanded without quotation in twofindinvocations. Bash therefore applies word splitting and pathname expansion to its contents before startingfind.This does not cause shell control characters to be reparsed as shell syntax, but it allows one supplied argument to become multiple arguments in the resulting
findcommand. Becausefindtreats arguments such as-exec,-delete, and-fprintas executable actions, an attacker can inject additionalfindpredicates and actions.The command dispatcher shifts the command name before invoking
cmd_stats, whilecmd_statsincorrectly reads$2rather than$1. As a result, the vulnerable value is reachable by supplying an additional argument, even though this differs from the documented interface. Storing the value indirdoes not mitigate the issue because the command directly expands${2:-.}without quotes.Attack Path
- An attacker causes the Skill or user to invoke
statswith an attacker-controlled extra argument. - The dispatcher removes
statsand passes the remaining arguments tocmd_stats. cmd_statsreads its second argument and expands it without quotes.- Bash splits the value into multiple arguments.
findinterprets injected arguments as expression actions.- An injected
-execaction starts a command with the privileges of th ...[truncated 1036 chars]
- An attacker causes the Skill or user to invoke
- Remediation
View remediation
Remediation Suggestions
-
Use the local
dirvariable and quote it in every command:bash cmd_stats() { local dir="${1:-}" [ -z "$dir" ] && die "Usage: $SCRIPT_NAME stats <dir>" echo 'Files:' find "$dir" -type f \( -name '*.py' -o -name '*.js' -o -name '*.sh' \) -print | wc -l echo 'Lines:' find "$dir" -type f \( -name '*.py' -o -name '*.js' -o -name '*.sh' \) \ -exec cat -- {} + 2>/dev/null | wc -l } -
Correct the positional parameter from
$2to$1, matching the dispatcher aftershift. -
Add parentheses to the first
findexpression so-type fapplies to every filename alternative. -
Reject unexpected extra arguments to prevent ambiguous command parsing.
-
Add tests using paths containing spaces, wildcard characters, leading hyphens, and strings resembling
findactions.
-
