From 4428b014f772b04219c90ddeda5d2c95c0fb55ef Mon Sep 17 00:00:00 2001 From: "sec-check[bot]" Date: Fri, 28 Aug 2026 10:07:29 -0400 Subject: [PATCH] [sec-check] fix: verify SHA-256 before installing cosign release asset install-cosign downloaded the cosign binary and installed it executable (optionally via sudo) with no integrity check. Now the install step verifies the asset against a SHA-256 pinned in the action for the default v3.0.6 release (values cross-checked against upstream cosign_checksums.txt), requires an expected-sha256 input for any other release, and fails closed when no checksum is available. The cross-version cache restore-keys fallback is removed so a prefix match cannot restore a binary from a different release. Refs #433 Signed-off-by: sec-check[bot] --- .github/actions/install-cosign/action.yml | 33 +++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/actions/install-cosign/action.yml b/.github/actions/install-cosign/action.yml index 56d38489..504aa2ef 100644 --- a/.github/actions/install-cosign/action.yml +++ b/.github/actions/install-cosign/action.yml @@ -15,6 +15,10 @@ inputs: description: "Use sudo when installing the binary" required: false default: "false" + expected-sha256: + description: "SHA-256 of the release asset. Required when cosign-release is not a pinned known release." + required: false + default: "" runs: using: "composite" @@ -40,8 +44,8 @@ runs: with: path: ${{ steps.prepare.outputs.install-dir }} key: cosign-${{ runner.os }}-${{ runner.arch }}-${{ steps.prepare.outputs.release }} - restore-keys: | - cosign-${{ runner.os }}-${{ runner.arch }}- + # No restore-keys: a prefix match could restore a binary from a + # different cosign release than the one requested. - name: Install cosign if: steps.cache.outputs.cache-hit != 'true' @@ -50,6 +54,7 @@ runs: COSIGN_RELEASE: ${{ steps.prepare.outputs.release }} INSTALL_DIR: ${{ steps.prepare.outputs.install-dir }} USE_SUDO: ${{ inputs.use-sudo }} + EXPECTED_SHA256: ${{ inputs.expected-sha256 }} run: | set -euo pipefail binary="${INSTALL_DIR}/cosign" @@ -71,6 +76,17 @@ runs: ;; esac + # Pinned SHA-256 for known releases (from cosign_checksums.txt in the + # upstream release). Any other release requires expected-sha256 input. + if [ -z "${EXPECTED_SHA256}" ]; then + case "${COSIGN_RELEASE}:${os}:${arch}" in + v3.0.6:linux:amd64) EXPECTED_SHA256="c956e5dfcac53d52bcf058360d579472f0c1d2d9b69f55209e256fe7783f4c74" ;; + v3.0.6:linux:arm64) EXPECTED_SHA256="bedac92e8c3729864e13d4a17048007cfafa79d5deca993a43a90ffe018ef2b8" ;; + v3.0.6:darwin:amd64) EXPECTED_SHA256="4c3e7af8372d3ca3296e62fa56f23fcbb5721cc6ac1827900d398f110d7cd280" ;; + v3.0.6:darwin:arm64) EXPECTED_SHA256="5fadd012ae6381a6a29ff86a7d39aa873878852f1073fc90b15995961ecfb084" ;; + esac + fi + asset_url="https://github.com/sigstore/cosign/releases/download/${COSIGN_RELEASE}/cosign-${os}-${arch}" tmp_dir="$(mktemp -d)" tmp_file="${tmp_dir}/cosign" @@ -85,6 +101,19 @@ runs: done if [ -s "${tmp_file}" ]; then + if [ -z "${EXPECTED_SHA256}" ]; then + echo "No pinned SHA-256 for ${COSIGN_RELEASE} ${os}/${arch} and no expected-sha256 input given." >&2 + echo "Refusing to install an unverified cosign binary." >&2 + exit 1 + fi + actual_sha256="$(sha256sum "${tmp_file}" | awk '{print $1}')" + if [ "${actual_sha256}" != "${EXPECTED_SHA256}" ]; then + echo "SHA-256 mismatch for cosign-${os}-${arch} (${COSIGN_RELEASE}):" >&2 + echo " expected: ${EXPECTED_SHA256}" >&2 + echo " actual: ${actual_sha256}" >&2 + exit 1 + fi + echo "SHA-256 verified: ${actual_sha256}" install_cmd=(install) if [ "${USE_SUDO}" = "true" ]; then install_cmd=(sudo install)