Follow-up from the #376 (PR #450) security review — MEDIUM, deferred so #450 could land with the fail-closed core + the rollback guard.
verify_release_images (pithead) runs cosign verify --key cosign.pub …:${STACK_VERSION} on each of the 5 image tags, then stack_upgrade does PITHEAD_PULL=always compose up, which resolves the same tag in a separate registry dial. A tampered/compromised registry can serve the signed manifest to cosign and a different manifest to docker moments later — the verification and the pull are not bound to the same bytes.
Fix: capture the digest cosign verified and assert the post-pull local image digest matches it (or verify + pull strictly by digest, e.g. resolve each tag→digest once, cosign-verify the digest, and compose against the digest-pinned refs). The dashboard bundle path already anchors on the downloaded file itself, so this is the CLI/image leg specifically.
Refs #376, PR #450, SECURITY.md (the "verify-then-pull window" note).
Follow-up from the #376 (PR #450) security review — MEDIUM, deferred so #450 could land with the fail-closed core + the rollback guard.
verify_release_images(pithead) runscosign verify --key cosign.pub …:${STACK_VERSION}on each of the 5 image tags, thenstack_upgradedoesPITHEAD_PULL=always compose up, which resolves the same tag in a separate registry dial. A tampered/compromised registry can serve the signed manifest to cosign and a different manifest to docker moments later — the verification and the pull are not bound to the same bytes.Fix: capture the digest cosign verified and assert the post-pull local image digest matches it (or verify + pull strictly by digest, e.g. resolve each tag→digest once, cosign-verify the digest, and
composeagainst the digest-pinned refs). The dashboard bundle path already anchors on the downloaded file itself, so this is the CLI/image leg specifically.Refs #376, PR #450,
SECURITY.md(the "verify-then-pull window" note).