T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/dev-serve.sh:265
- Finding
- Shell Command Injection Through the Unvalidated Port Argument<![CDATA[ ## Vulnerability Details **File Location**: `scripts/dev-serve.sh`, lines 73-87 and 265-293 **Vulnerability Type**: OS command injection through shell command construction **Risk Level**: High ### Vulnerable Code ```bash detect_dev_cmd() { local repo="$1" local port="$2" # Check for override if [[ -n "${DEV_CMD:-}" ]]; then echo "$DEV_CMD" return fi # Detect package manager local pm="npm" if [[ -f "$repo/pnpm-lock.yaml" ]]; then pm="pnpm" elif [[ -f "$repo/bun.lockb" ]] || [[ -f "$repo/bun.lock" ]]; then pm="bun" elif [[ -f "$repo/yarn.lock" ]]; then pm="yarn" fi # Read dev script local dev_script dev_script=$(jq -r '.scripts.dev // empty' "$repo/package.json" 2>/dev/null) if [[ -z "$dev_script" ]]; then echo >&2 "Error: No 'dev' script in package.json. Set DEV_CMD env var." exit 1 fi # Check if it's a vite-based server (needs --host and --port flags) if echo "$dev_script" | grep -qiE '(vite|next|nuxt|svelte)'; then echo "$pm run dev -- --host 0.0.0.0 --port $port" else echo "PORT=$port $pm run dev" fi } ``` ```bash cmd_up() { local repo="${1:?missing repo path}" local repo_abs repo_abs=$(cd "$repo" 2>/dev/null && pwd) || { echo "Error: '$repo' not found" >&2; exit 1; } local name name=$(basename "$repo_abs") local port="${2:-$(next_port)}" # Check if already running if jq -e ".\"$name\"" "$STATE_FILE" >/dev/null 2>&1; then echo "Error: '$name' is already running. Use 'dev-serve down $name' first or 'dev-serve restart $name'." >&2 exit 1 fi local dev_cmd dev_cmd=$(detect_dev_cmd "$repo_abs" "$port") local subdomain="${name}.${DOMAIN}" echo "🚀 Starting ${name}" echo " Repo: ${repo_abs}" echo " Port: ${port}" echo " Command: ${dev_cmd}" echo " URL: https://${subdomain}" echo "" # Patch Vite allowedHosts if needed patch_vite_allowed_hosts "$repo_abs" "$subdomain" # Create tmux session with dev server local sessi ...[truncated 2335 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate an explicitly supplied port before using it anywhere: ```bash if [[ ! "$port" =~ ^[0-9]+$ ]] || (( port < 1 || port > 65535 )); then echo "Error: port must be an integer from 1 to 65535" >&2 exit 1 fi ``` 2. Do not submit assembled command strings to an interactive shell. Start tmux with an executable and separately quoted arguments where possible. 3. If shell interpretation is unavoidable, construct the command from trusted fixed tokens and escape every variable using `printf '%q'`. 4. Apply equivalent validation to auto-assigned and state-loaded ports. 5. Check that the selected port is not already listening, rather than checking only the state file and Caddyfile. 6. Add regression tests covering semicolons, command substitutions, whitespace, newlines, negative numbers, oversized values, and nonnumeric port arguments. ]]>
