fix(ci): harden against template injection and credential exposure#2514
Merged
Conversation
Move ${{ context }} expressions to env: variables to prevent shell
injection in run: blocks. Affects matrix.cfg/matrix.package
(workflow-controlled) and github.workspace (runner-controlled)
expansions flagged by zizmor pedantic persona.
Files changed:
- e2e.yaml: matrix.cfg in Build package step
- melange-test-pipelines.yaml: github.workspace in install-melange step
- wolfi-presubmit.yaml: github.workspace in install step; matrix.package
in wolfictl bump, bubblewrap build/test, QEMU build/test, xattr test,
and CVE scan steps (9 steps total)
Refs: PSEC-923
Prevents GitHub token from persisting in the git config after checkout, reducing credential exposure window per the artipacked zizmor rule. All write operations in release.yaml pass their token explicitly: - mathieudutour/github-tag-action receives github_token: input - make release receives GITHUB_TOKEN: env var - git fetch --tags is read-only; repo is public (comment added) No downstream step relies on the git credential store. Files changed (12 checkout steps across 7 workflows): - build.yaml: build job checkout - e2e.yaml: rebuild job checkout - go-tests.yaml: test job checkout - melange-test-pipelines.yaml: build-melange and test-packages job checkouts (3 total, including mid-job re-checkout) - release.yaml: both checkouts in release job (initial + tag-specific) - verify.yaml: golangci job checkout - wolfi-presubmit.yaml: build-melange checkout, wolfi-dev/os checkout, and conditional melange-src checkout in build-packages job Refs: PSEC-923
- .github/zizmor.yml (new): suppress concurrency-limits (9 findings), anonymous-definition (1 finding), and undocumented-permissions (1 finding) — all pedantic-only with no exploitable security impact. Sets dependabot-cooldown threshold to 3 days to match new cooldown config in dependabot.yml. - .github/workflows/zizmor.yaml: add persona: pedantic to zizmor-action step so CI catches all template expansion findings, not just attacker-controlled sources. Also extend path triggers to include .github/dependabot.yml and .github/zizmor.yml. - .github/dependabot.yml: add cooldown: default-days: 3 to both package ecosystems (gomod and github-actions) to satisfy dependabot-cooldown zizmor rule. Refs: PSEC-923
- .actionlint.yaml (new): register ubuntu-latest-8-core as a known custom runner label, suppressing the runner-label warning in melange-test-pipelines.yaml and wolfi-presubmit.yaml. - release.yaml: quote $GITHUB_OUTPUT redirections (SC2086) in the Check if any changes since last release step. Four occurrences of >> $GITHUB_OUTPUT corrected to >> "$GITHUB_OUTPUT". - wolfi-presubmit.yaml: quote $(pwd) in docker run -v arguments (SC2046) in the Test installable and Scan for CVEs step. Four docker run invocations updated to use "$(pwd)":/work. Refs: PSEC-923
Resolves ref-version-mismatch zizmor findings by annotating SHA-pinned action refs with their corresponding version tag or branch name. Refs: PSEC-923
egibs
approved these changes
May 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This patch series addresses GitHub Actions security findings from the PSEC-923 sweep
of
chainguard-dev/melange. Five commits are included.Sweep date: 2026-05-02. zizmor version: 1.24.1 (auditor persona for sweep;
patches configure pedantic persona for ongoing CI).
Patches
0001 — fix(ci): resolve template injection findings
Fixes 18
template-injectionzizmor findings across three workflow files by moving${{ context }}expressions intoenv:variables and referencing them via$VAR_NAMEin
run:blocks. All injected values are workflow-controlled (matrix.cfg,matrix.package,github.workspace) rather than attacker-controlled, but the pedanticpersona correctly flags them as a code hygiene concern.
Files changed:
e2e.yaml—${{matrix.cfg}}in the "Build package" step (1 step, 2 occurrences)melange-test-pipelines.yaml—${{ github.workspace }}in the install-melange stepwolfi-presubmit.yaml—${{ github.workspace }}in install-melange step;${{ matrix.package }}in 8 additional steps: wolfictl bump, bubblewrap build/test,QEMU build/test, xattr verification, and the "Test installable and Scan for CVEs" step
All
env:blocks are placed beforerun:, and all generated shell references usedouble-quoted
"$VAR_NAME"form where appropriate. Stepname:fields containing${{ matrix.package }}(e.g.,Make package ${{ matrix.package }} with QEMU Runner)are intentionally preserved — zizmor does not flag them and they keep matrix rows
distinguishable in the Actions UI.
0002 — fix(ci): add persist-credentials: false to checkout steps
Fixes 12
artipackedzizmor findings across 7 workflow files by addingpersist-credentials: falseto all checkout steps that did not already have it.Artipacked checkouts fixed:
build.yaml: build job (1 checkout)e2e.yaml: rebuild job (1 checkout)go-tests.yaml: test job (1 checkout)melange-test-pipelines.yaml: build-melange job (1 checkout) and test-packages job(2 checkouts — initial + mid-job re-checkout)
release.yaml: release job (2 checkouts — initial + tag-specific)verify.yaml: golangci job (1 checkout)wolfi-presubmit.yaml: build-melange job (1 checkout), build-packages job —wolfi-dev/os checkout and conditional melange-src checkout (2 checkouts)
Release workflow rationale: Both checkout steps in
release.yamlreceivepersist-credentials: falsebecause all downstream write operations pass their tokenexplicitly:
mathieudutour/github-tag-actionreceivesgithub_token:as a step input,and
make release(which runs goreleaser) receivesGITHUB_TOKENas an env var.The
git fetch --tagsstep is read-only on a public repository; a comment was addedto document this assumption. See
manual-review.mdfor full reasoning.0003 — fix(ci): add pedantic persona, zizmor config, and dependabot cooldown
Configures ongoing zizmor CI to use the pedantic persona (catching all template
expansions, not just attacker-controlled sources), suppresses noisy pedantic-only rules
with no security impact, adds a 3-day dependabot cooldown, and extends CI path triggers
to cover config file changes.
Changes:
.github/zizmor.yml(new file): suppressconcurrency-limits(9 findings),anonymous-definition(1 finding), andundocumented-permissions(1 finding) —all pedantic-only with no exploitable security impact. Sets
dependabot-cooldownthreshold to 3 days to match the
dependabot.ymlcooldown..github/workflows/zizmor.yaml: addpersona: pedanticto thezizmor-actionstep. Extend
paths:triggers to include.github/dependabot.ymland.github/zizmor.ymlso changes to those files trigger the zizmor check..github/workflows/actionlint.yaml: extendpaths:triggers to include.github/dependabot.ymland.github/zizmor.yml..github/dependabot.yml: addcooldown: default-days: 3to both thegomodandgithub-actionspackage ecosystems, satisfying thedependabot-cooldownzizmor rule.0004 — fix(ci): address actionlint and shellcheck findings
Fixes mechanical actionlint/shellcheck findings.
Changes:
.actionlint.yaml(new file): registersubuntu-latest-8-coreas a known customrunner label, suppressing the false-positive
runner-labelwarning that appeared formelange-test-pipelines.yamlandwolfi-presubmit.yaml.release.yaml: quote$GITHUB_OUTPUTin redirect operators (SC2086). Fouroccurrences of
>> $GITHUB_OUTPUTcorrected to>> "$GITHUB_OUTPUT"in the"Check if any changes since last release" step.
wolfi-presubmit.yaml: quote$(pwd)in docker run-varguments (SC2046). Allfour docker run invocations in "Test installable and Scan for CVEs" updated to use
"$(pwd)":/work.0005 — fix(ci): add missing version comments to SHA-pinned action refs
Resolves
ref-version-mismatchzizmor findings by annotating SHA-pinned action refswith their corresponding version tag or branch name (looked up via the GitHub API).
Findings Not Patched
cache-poisoningunpinned-imagesalpine:latestrequires SHA lookupref-version-mismatchstale-action-refsconcurrency-limitsanonymous-definitionundocumented-permissionsReferences
Refs: PSEC-923