T09 · Insecure Skill Coding Practices
- Location
scripts/batch-analyze.sh:25- Finding
Unsafe pathname splitting can submit unintended local files to Gemini
- Content
View full analysis
Vulnerability Details
File Location:
scripts/batch-analyze.sh, lines 25–59
Vulnerability Type: Unsafe shell word splitting and pathname expansion
Risk Level: Mediumbash # Find all code files FILES=$(find "$INPUT_DIR" -type f \( -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.jsx" -o -name "*.py" -o -name "*.go" \) | grep -v node_modules | sort) TOTAL=$(echo "$FILES" | wc -l) COUNT=0 if [ "$TOTAL" -eq 0 ]; then echo "⚠️ No code files found in $INPUT_DIR" exit 1 fi echo "📊 Found $TOTAL files to analyze" echo "" # Process each file for file in $FILES; do COUNT=$((COUNT + 1)) # Create output filename SAFE_NAME=$(echo "$file" | sed 's/[^a-zA-Z0-9_.-]/-/g') OUTPUT_FILE="$OUTPUT_DIR/${SAFE_NAME}.md" echo "[$COUNT/$TOTAL] Analyzing: $file" case "$OPERATION" in explain) gemini code --explain "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;; review) gemini code --review "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;; fix) gemini code --fix "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;; test) gemini code --test "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;;Technical Analysis
The script stores newline-delimited output from
findin the scalar variableFILESand subsequently expands it without quotes infor file in $FILES. Bash applies word splitting and pathname expansion to this expansion. Consequently, filenames containing spaces, tabs, newlines, or glob metacharacters are not preserved as individual pathnames.This behavior can transform one path returned by the extension-restricted
findcommand into multiple arguments. Some resulting tokens can identify files that did not match the original code-file filter. Each token is then passed to the network-connectedgeminiprocess, potentially causing an uninten ...[truncated 1971 chars]- Remediation
View remediation
Remediation Suggestions
Process filenames as NUL-delimited records and avoid storing the result of
findin a scalar variable:bash COUNT=0 while IFS= read -r -d '' file; do COUNT=$((COUNT + 1)) SAFE_NAME=$(printf '%s' "$file" | sed 's/[^a-zA-Z0-9_.-]/-/g') OUTPUT_FILE="$OUTPUT_DIR/${SAFE_NAME}.md" case "$OPERATION" in explain) gemini code --explain "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;; review) gemini code --review "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;; fix) gemini code --fix "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;; test) gemini code --test "$file" --format markdown > "$OUTPUT_FILE" 2>/dev/null ;; esac done < <( find "$INPUT_DIR" -type f \ \( -name '*.js' -o -name '*.ts' -o -name '*.tsx' -o -name '*.jsx' \ -o -name '*.py' -o -name '*.go' \) \ -not -path '*/node_modules/*' -print0 )Additional hardening should include:
- Use
mapfile -d ''if a precomputed file count is required. - Replace
grep -v node_moduleswith a structuralfindexclusion so paths merely containing that text are not incorrectly discarded. - Add a hash of the complete source path to each output filename to prevent normalization collisions.
- Reject symbolic links or resolve and verify canonical paths if analysis must remain within
INPUT_DIR. - Where supported by the Gemini CLI, place
--before positional path arguments to prevent filenames beginning with a hyphen from being interpreted as options. - Clearly warn users that selected files are transmitted to an external service and recommend scanning only trusted directory trees.
- Use
