mirror of
https://github.com/storytold/craft-common-actions.git
synced 2026-11-03 09:18:12 +00:00
security(actions): stop evaluating tool-version inputs as shell/pwsh source (#45)
* security(actions): stop evaluating tool-version inputs as shell/pwsh source
The install-wix, install-nfpm, install-trunk, and packaging-lint composite
actions interpolated their *-version (and deb-arch) inputs directly into
Bash/PowerShell source when constructing download URLs. A command substitution
or subexpression in those values executed on the runner before any checksum
verification (CWE-78).
install-trunk additionally placed the version into a URL path component, so
path-traversal segments could point both the archive and its fallback checksum
at an attacker-controlled repository (CWE-23).
Fixes:
- Pass every version/arch input through the step `env:` and read it with quoted
variable expansions instead of GitHub `${{ }}` interpolation in script bodies.
- Validate a strict version grammar (and an allow-list for deb-arch) before the
value is used, which also excludes slashes and other URL path-traversal
characters so the download publisher stays fixed.
No change to default versions, pinned checksums, or install behavior.
* security(actions): anchor version validation against the whole value
Address review feedback:
- The bash version checks used `printf %s | grep -Eq '^...$'`, which matches
line-by-line. A value like `2.49.0\ninvalid` passed and then flowed into the
download URL. Switch to a bash `[[ =~ ^...$ ]]` test, which anchors the entire
string and rejects any value containing a newline. Applied to install-nfpm,
install-trunk, and packaging-lint.
- The install-wix PowerShell check used `$`, which in .NET also matches before a
trailing newline. Use `\z` (absolute end of input) so a trailing-newline value
cannot bypass validation.
This commit is contained in:
1 parent
3a54b3bbb8
commit
2446e3bd4f
4 files changed
+52
-12
No files matched your search
@@ -16,11 +16,25 @@ runs:
|
||||
steps:
|
||||
- name: Download and verify nfpm
|
||||
shell: bash
|
||||
env:
|
||||
NFPM_VERSION: ${{ inputs.nfpm-version }}
|
||||
DEB_ARCH: ${{ inputs.deb-arch }}
|
||||
run: |
|
||||
deb_url="https://github.com/goreleaser/nfpm/releases/download/v${{ inputs.nfpm-version }}/nfpm_${{ inputs.nfpm-version }}_${{ inputs.deb-arch }}.deb"
|
||||
version="$NFPM_VERSION"
|
||||
arch="$DEB_ARCH"
|
||||
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
|
||||
echo "::error::invalid nfpm-version '$version'"
|
||||
exit 1
|
||||
fi
|
||||
case "$arch" in
|
||||
amd64 | arm64) ;;
|
||||
*) echo "::error::invalid deb-arch '$arch'"; exit 1 ;;
|
||||
esac
|
||||
|
||||
deb_url="https://github.com/goreleaser/nfpm/releases/download/v${version}/nfpm_${version}_${arch}.deb"
|
||||
curl --proto '=https' --proto-redir =https -fsSL -o "$RUNNER_TEMP/nfpm.deb" "$deb_url"
|
||||
|
||||
case "${{ inputs.nfpm-version }}:${{ inputs.deb-arch }}" in
|
||||
case "${version}:${arch}" in
|
||||
"2.48.0:amd64")
|
||||
expected="787af76e172dd5fc7cedf4d7c5a090a2f62be9001557a4db1103e270f90ddefd"
|
||||
;;
|
||||
@@ -34,8 +48,8 @@ runs:
|
||||
expected="27419eb382695a7942be8ad52259f3ec1854fad001b3ae4baed34ce39a223b97"
|
||||
;;
|
||||
*)
|
||||
curl --proto '=https' --proto-redir =https -fsSL -o "$RUNNER_TEMP/checksums.txt" "https://github.com/goreleaser/nfpm/releases/download/v${{ inputs.nfpm-version }}/checksums.txt"
|
||||
expected=$(grep -E "nfpm_${{ inputs.nfpm-version }}_${{ inputs.deb-arch }}\.deb" "$RUNNER_TEMP/checksums.txt" | awk '{print $1}')
|
||||
curl --proto '=https' --proto-redir =https -fsSL -o "$RUNNER_TEMP/checksums.txt" "https://github.com/goreleaser/nfpm/releases/download/v${version}/checksums.txt"
|
||||
expected=$(grep -E "nfpm_${version}_${arch}\.deb" "$RUNNER_TEMP/checksums.txt" | awk '{print $1}')
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
@@ -12,10 +12,22 @@ runs:
|
||||
steps:
|
||||
- name: Install trunk
|
||||
shell: bash
|
||||
env:
|
||||
TRUNK_VERSION: ${{ inputs.trunk-version }}
|
||||
run: |
|
||||
tar_url="https://github.com/trunk-rs/trunk/releases/download/v${{ inputs.trunk-version }}/trunk-x86_64-unknown-linux-gnu.tar.gz"
|
||||
version="$TRUNK_VERSION"
|
||||
# Restrict the version to a single safe release-tag component. This keeps
|
||||
# the value from carrying slashes or other URL path-traversal segments
|
||||
# that could redirect downloads to an attacker-controlled repository. The
|
||||
# bash regex anchors the whole string, so values containing a newline are
|
||||
# rejected (unlike a line-oriented grep check).
|
||||
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
|
||||
echo "::error::invalid trunk-version '$version'"
|
||||
exit 1
|
||||
fi
|
||||
tar_url="https://github.com/trunk-rs/trunk/releases/download/v${version}/trunk-x86_64-unknown-linux-gnu.tar.gz"
|
||||
curl --proto '=https' --proto-redir =https -fsSL -o "$RUNNER_TEMP/trunk.tar.gz" "$tar_url"
|
||||
case "${{ inputs.trunk-version }}" in
|
||||
case "$version" in
|
||||
"0.21.14")
|
||||
expected="f2b4680cd239693a646a2795e4633c625328d7b2a044fbe749fa3a2fe9e7036b"
|
||||
;;
|
||||
|
||||
@@ -16,9 +16,16 @@ runs:
|
||||
steps:
|
||||
- name: Install WiX
|
||||
shell: pwsh
|
||||
env:
|
||||
WIX_VERSION: ${{ inputs.wix-version }}
|
||||
INSTALL_EXTENSIONS: ${{ inputs.install-extensions }}
|
||||
run: |
|
||||
$version = "${{ inputs.wix-version }}"
|
||||
$version = $env:WIX_VERSION
|
||||
if ($version -notmatch '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?\z') {
|
||||
Write-Output "::error::invalid wix-version '$version'"
|
||||
exit 1
|
||||
}
|
||||
dotnet tool install --global wix --version $version
|
||||
if ("${{ inputs.install-extensions }}" -eq "true") {
|
||||
if ($env:INSTALL_EXTENSIONS -eq "true") {
|
||||
wix extension add -g "WixToolset.UI.wixext/$version" "WixToolset.Util.wixext/$version"
|
||||
}
|
||||
@@ -12,18 +12,25 @@ runs:
|
||||
steps:
|
||||
- name: Install tools
|
||||
shell: bash
|
||||
env:
|
||||
ACTIONLINT_VERSION: ${{ inputs.actionlint-version }}
|
||||
run: |
|
||||
version="$ACTIONLINT_VERSION"
|
||||
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
|
||||
echo "::error::invalid actionlint-version '$version'"
|
||||
exit 1
|
||||
fi
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends shellcheck desktop-file-utils appstream libxml2-utils python3-yaml
|
||||
tar_url="https://github.com/rhysd/actionlint/releases/download/v${{ inputs.actionlint-version }}/actionlint_${{ inputs.actionlint-version }}_linux_amd64.tar.gz"
|
||||
tar_url="https://github.com/rhysd/actionlint/releases/download/v${version}/actionlint_${version}_linux_amd64.tar.gz"
|
||||
curl --proto '=https' --proto-redir =https -fsSL -o "$RUNNER_TEMP/actionlint.tar.gz" "$tar_url"
|
||||
case "${{ inputs.actionlint-version }}" in
|
||||
case "$version" in
|
||||
"1.7.12")
|
||||
expected="8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8"
|
||||
;;
|
||||
*)
|
||||
curl --proto '=https' --proto-redir =https -fsSL -o "$RUNNER_TEMP/checksums.txt" "https://github.com/rhysd/actionlint/releases/download/v${{ inputs.actionlint-version }}/actionlint_${{ inputs.actionlint-version }}_checksums.txt"
|
||||
expected=$(grep -E "actionlint_${{ inputs.actionlint-version }}_linux_amd64\.tar\.gz" "$RUNNER_TEMP/checksums.txt" | awk '{print $1}')
|
||||
curl --proto '=https' --proto-redir =https -fsSL -o "$RUNNER_TEMP/checksums.txt" "https://github.com/rhysd/actionlint/releases/download/v${version}/actionlint_${version}_checksums.txt"
|
||||
expected=$(grep -E "actionlint_${version}_linux_amd64\.tar\.gz" "$RUNNER_TEMP/checksums.txt" | awk '{print $1}')
|
||||
;;
|
||||
esac
|
||||
echo "$expected $RUNNER_TEMP/actionlint.tar.gz" | sha256sum -c -
|
||||
|
||||
Reference in new issue
Block a user