T09 · Insecure Skill Coding Practices
- Location
build.sh:10- Finding
PowerShell Command Injection Through Unvalidated Build Version
- Content
View full analysis
Building $ZIP_NAME (ver=$VER)" echo " Source : $SRC_DIR" echo " Output : $OUT_DIR/$ZIP_NAME" mkdir -p "$OUT_DIR" mkdir -p "$STAGE_DIR" # ... cd "$(dirname "$STAGE_DIR")" if command -v zip >/dev/null 2>&1; then zip -qr "$OUT_DIR/$ZIP_NAME" "$(basename "$STAGE_DIR")" elif command -v 7z >/dev/null 2>&1; then 7z a -tzip "$OUT_DIR/$ZIP_NAME" "$(basename "$STAGE_DIR")" >/dev/null elif command -v powershell.exe >/dev/null 2>&1 || command -v powershell >/dev/null 2>&1; then PSH="$(command -v powershell.exe 2>/dev/null || command -v powershell)" WIN_SRC="$(cygpath -w "$STAGE_DIR" 2>/dev/null || echo "$STAGE_DIR")" WIN_OUT="$(cygpath -w "$OUT_DIR/$ZIP_NAME" 2>/dev/null || echo "$OUT_DIR/$ZIP_NAME")" "$PSH" -NoProfile -Command "Compress-Archive -Path '${WIN_SRC}' -DestinationPath '${WIN_OUT}' -Force" ``` ### Technical Analysis The build version can be supplied directly as the first command-line argument and is not validated. It is incorporated into both `STAGE_DIR` and `OUT_DIR`, which subsequently become `WIN_SRC` and `WIN_OUT`. In the PowerShell fallback, these paths are interpolated into PowerShell source code enclosed by single quotes: ```powershell Compress-Archive -Path '${WIN_SRC}' -DestinationPath '${WIN_OUT}' -Force ``` Shell-level quoting does not make these values safe for the PowerShell parser. A version containing a single quote can terminate the PowerShell string, after which semicolons and additional PowerShell statements can be injected. Quoting ...[truncated 1712 chars]- Remediation
View remediation
&2 exit 1 fi ``` 2. Reject quotes, whitespace, path separators, control characters, shell metacharacters, and PowerShell metacharacters even if a broader version syntax is later supported. 3. Do not generate PowerShell source code by interpolating untrusted paths. Pass values as positional arguments instead: ```bash "$PSH" -NoProfile -Command \ 'param($Source, $Destination) Compress-Archive -LiteralPath $Source -DestinationPath $Destination -Force' \ "$WIN_SRC" "$WIN_OUT" ``` 4. Prefer `-LiteralPath` where supported so wildcard characters in paths are not interpreted. 5. Apply the same validation to versions extracted from `SKILL.md`; repository content may also be attacker-controlled in compromised branches or pull requests. 6. Add regression tests using versions containing quotes, semicolons, whitespace, newlines, wildcard characters, and path separators. The build must reject every malformed value before creating directories or invoking an archiver. 7. Run release builds with a minimally privileged account and avoid exposing unrelated deployment credentials or signing secrets to the packaging step. ]]>
