Repository: dotnet/runtime
File: src/tasks/WasmAppBuilder/generate-coreclr-helpers.sh (Shell)

Code before:
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "$script_dir/../../.." && pwd)"

echo "Configuration: $configuration"
echo "Repo root: $repo_root"

if [[ -n "$scan_path_override" ]]; then
    scan_path="$scan_path_override"
else
    scan_path="$repo_root/artifacts/bin/testhost/net11.0-browser-$configuration-wasm/shared/Microsoft.NETCore.App/11.0.0/"
fi

if [[ ! -d "$scan_path" ]]; then
    echo "Error: Scan path does not exist: $scan_path"
    echo "Please build the runtime first using: ./build.sh clr+libs -os browser -c $configuration"
    exit 1
fi

cd "$repo_root"
echo "Scan path: $scan_path"

# Run the generator
echo "Running generator..."
generator_cmd="./dotnet.sh build /t:RunGenerator /p:RuntimeFlavor=CoreCLR /p:GeneratorOutputPath=$repo_root/src/coreclr/vm/wasm/ /p:AssembliesScanPath=$scan_path src/tasks/WasmAppBuilder/WasmAppBuilder.csproj"
echo "$generator_cmd"
$generator_cmd

echo "Done!"


Review comment (security):
The `generator_cmd` string is built by concatenating untrusted inputs (e.g., `scan_path` from `-s/--scan-path` and `configuration` from `-c/--configuration`) into a single shell command and then executed via `$generator_cmd`. If an attacker can influence these arguments, they can inject shell metacharacters (such as `;`, `&&`, or ``$(...)``) into `scan_path` or `configuration` to execute arbitrary commands in the context of this script. To prevent command injection, avoid constructing a single command string and instead invoke `./dotnet.sh` directly with a properly quoted argument list so that user-controlled data cannot be interpreted as shell syntax.
```suggestion
echo "./dotnet.sh build /t:RunGenerator /p:RuntimeFlavor=CoreCLR /p:GeneratorOutputPath=$repo_root/src/coreclr/vm/wasm/ /p:AssembliesScanPath=$scan_path src/tasks/WasmAppBuilder/WasmAppBuilder.csproj"
./dotnet.sh build \
    /t:RunGenerator \
    /p:RuntimeFlavor=CoreCLR \
    "/p:GeneratorOutputPath=$repo_root/src/coreclr/vm/wasm/" \
    "/p:AssembliesScanPath=$scan_path" \
    src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
```

Code after:
config_lower="$(echo "$configuration" | tr '[:upper:]' '[:lower:]')"
case "$config_lower" in
    debug|release|checked)
        ;;
    *)
        echo "Error: Invalid configuration \"$configuration\". Must be Debug, Release, or Checked."
        exit 1
        ;;
esac

# Get the repo root (script is in src/tasks/WasmAppBuilder)
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "$script_dir/../../.." && pwd)"

echo "Configuration: $configuration"
echo "Repo root: $repo_root"

if [[ -n "$scan_path_override" ]]; then
    scan_path="$scan_path_override"
else
    scan_path="$repo_root/artifacts/bin/testhost/net11.0-browser-$configuration-wasm/shared/Microsoft.NETCore.App/11.0.0/"
fi

if [[ ! -d "$scan_path" ]]; then
    echo "Error: Scan path does not exist: $scan_path"
    echo "Please build the runtime first using: ./build.sh clr+libs -os browser -c $configuration"
    exit 1
fi

cd "$repo_root"
echo "Scan path: $scan_path"

# Run the generator - invoke directly without building a command string
echo "Running generator..."
echo "./dotnet.sh build /t:RunGenerator /p:RuntimeFlavor=CoreCLR /p:GeneratorOutputPath=$repo_root/src/coreclr/vm/wasm/ /p:AssembliesScanPath=$scan_path src/tasks/WasmAppBuilder/WasmAppBuilder.csproj"
./dotnet.sh build /t:RunGenerator /p:RuntimeFlavor=CoreCLR "/p:GeneratorOutputPath=$repo_root/src/coreclr/vm/wasm/" "/p:AssembliesScanPath=$scan_path" src/tasks/WasmAppBuilder/WasmAppBuilder.csproj

echo "Done!"