T09 · Insecure Skill Coding Practices
- Location
scripts/taildrop-get.sh:50- Finding
Command Injection Through User-Controlled Destination Path
- Content
View full analysis
Vulnerability Details
File Location:
scripts/taildrop-get.sh, lines 50–63
Vulnerability Type: Shell command injection through unsafe use ofeval
Risk Level: HighVulnerable Code
bash # Build command CMD="tailscale file get --conflict=$CONFLICT_MODE" if [ "$LOOP_MODE" = true ]; then CMD="$CMD --loop" fi CMD="$CMD \"$TARGET_DIR\"" echo "Downloading Taildrop files to: $TARGET_DIR" echo "Conflict mode: $CONFLICT_MODE" if [ "$LOOP_MODE" = true ]; then echo "Running in loop mode (Ctrl+C to stop)..." fi # Execute eval $CMDTARGET_DIRoriginates from an arbitrary positional command-line argument:bash *) TARGET_DIR="$1" shift ;;Technical Analysis
The script constructs a shell command as a string and executes it with
eval. Although the destination path is surrounded by embedded quotation marks,evalperforms an additional shell-parsing pass. Shell command substitutions withinTARGET_DIR, such as$(...), are therefore evaluated as commands rather than treated exclusively as literal path content.The earlier use of
mkdir -p "$TARGET_DIR"does not neutralize this payload. That command correctly treats the value as a literal path, but the same value is subsequently placed into the command string and reparsed byeval.For example, a destination argument containing
$(touch pwned)is initially accepted as a literal directory name. During theevaloperation, the command substitution executestouch pwned.Attack Path
-
An attacker convinces a user or automation agent to invoke the Skill with a crafted destination argument:
bash ./scripts/taildrop-get.sh '$(touch pwned)' -
The argument is assigned directly to
TARGET_DIR. -
mkdir -p "$TARGET_DIR"creates a directory with the literal crafted name. -
The script incorporates the untrusted value into the
CMDstring. -
eval $CMD...[truncated 1033 chars]
-
- Remediation
View remediation
Remediation Suggestions
Remove
evaland represent the command as a Bash array. Array expansion preserves argument boundaries and prevents the destination path from being reparsed as shell syntax:bash CMD=(tailscale file get "--conflict=$CONFLICT_MODE") if [[ "$LOOP_MODE" == true ]]; then CMD+=(--loop) fi CMD+=("$TARGET_DIR") "${CMD[@]}"Additional hardening measures should include:
-
Retain the existing fixed allowlist for conflict modes rather than accepting arbitrary option values.
-
Use
--before the destination argument if the Tailscale CLI supports it, preventing paths beginning with a hyphen from being interpreted as options:bash CMD+=(-- "$TARGET_DIR") -
Avoid all string-based shell command assembly when any component can originate from user input.
-
Add regression tests using destination names containing command substitutions, spaces, quotation marks, semicolons, and leading hyphens, verifying that they are passed as literal arguments and never executed.
-
Run the Skill with the least privileges necessary and avoid invoking the entire script through
sudo.
-
