From 26501daa4e51b5055b3479f0a8756a34ee0cf984 Mon Sep 17 00:00:00 2001 From: guessthepw Date: Sun, 25 Jan 2026 09:34:24 -0500 Subject: [PATCH] Fix critical security vulnerabilities from audit - Rustup: Download script to temp file with shebang/size validation before execution, matching mise/ollama pattern (line 1119) - SKIP_EXPORTS: Refactor from embedded shell commands to base64-encoded list decoded safely in VM, eliminating injection risk (line 478) - Playwright symlink: Validate path is executable and within expected cache directory before creating system symlinks (line 1053) Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 7 ++++++ setup_env.sh | 62 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2639fa7..40bdede 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.0] - 2025-01-25 + +### Security +- Fix rustup pipe-to-shell vulnerability: now downloads to temp file with validation before execution +- Fix SKIP_EXPORTS command injection risk: refactored to use base64-encoded list instead of shell command string +- Fix Playwright symlink path validation: validates executable and path prefix before creating symlinks + ## [0.8.0] - 2025-01-25 ### Added diff --git a/setup_env.sh b/setup_env.sh index 9ad01c3..72f9479 100755 --- a/setup_env.sh +++ b/setup_env.sh @@ -390,12 +390,12 @@ if [[ "$(uname -s)" == "Darwin" ]]; then echo "" - # Build SKIP env var exports for unselected components - SKIP_EXPORTS="" + # Build list of skipped component IDs (space-separated, safe characters only) + # Security: Only hardcoded component IDs from COMP_IDS are used, no user input + SKIP_LIST="" for ((i=0; i/dev/null | head -1) - if [ -n "$pw_chrome" ]; then + local pw_chrome + pw_chrome=$(find "$HOME/.cache/ms-playwright" -name "chrome" -type f 2>/dev/null | head -1) + # Security: Validate the found path before creating symlinks + # - Must not be empty + # - Must be an executable file + # - Must be within the expected playwright cache directory + if [ -n "$pw_chrome" ] && [ -x "$pw_chrome" ] && [[ "$pw_chrome" == "$HOME/.cache/ms-playwright"* ]]; then [ ! -e /usr/local/bin/chromium ] && sudo ln -sf "$pw_chrome" /usr/local/bin/chromium [ ! -e /usr/local/bin/google-chrome ] && sudo ln -sf "$pw_chrome" /usr/local/bin/google-chrome echo "Using Playwright's bundled Chromium" @@ -1115,8 +1132,29 @@ install_base_deps() { if command_exists cargo; then cargo install watchexec-cli else - # Fallback: install cargo first, then watchexec - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + # Security: Download rustup script first, validate, then execute (Issue #3) + # Same pattern as mise/ollama - never pipe directly to shell + local rustup_script + rustup_script=$(mktemp) + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o "$rustup_script" + + # Verify it's a shell script + if ! head -1 "$rustup_script" | grep -qE '^#!\s*/(bin|usr/bin)/(env\s+)?(ba)?sh'; then + log_error "Downloaded rustup script doesn't have a valid shell shebang" + rm -f "$rustup_script" + return 1 + fi + # Check file size is reasonable (not empty, not huge) + local script_size + script_size=$(wc -c < "$rustup_script") + if [ "$script_size" -lt 100 ] || [ "$script_size" -gt 2000000 ]; then + log_error "Downloaded rustup script has suspicious size: $script_size bytes" + rm -f "$rustup_script" + return 1 + fi + + sh "$rustup_script" -y + rm -f "$rustup_script" source "$HOME/.cargo/env" cargo install watchexec-cli fi