Skip to content

fix(ci): harden against template injection and credential exposure#2514

Merged
egibs merged 5 commits into
mainfrom
security/psec-923-melange
May 5, 2026
Merged

fix(ci): harden against template injection and credential exposure#2514
egibs merged 5 commits into
mainfrom
security/psec-923-melange

Conversation

@stevebeattie
Copy link
Copy Markdown
Member

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-injection zizmor findings across three workflow files by moving
${{ context }} expressions into env: variables and referencing them via $VAR_NAME
in run: blocks. All injected values are workflow-controlled (matrix.cfg,
matrix.package, github.workspace) rather than attacker-controlled, but the pedantic
persona 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 step
  • wolfi-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 before run:, and all generated shell references use
double-quoted "$VAR_NAME" form where appropriate. Step name: 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 artipacked zizmor findings across 7 workflow files by adding
persist-credentials: false to 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.yaml receive
persist-credentials: false because all downstream write operations pass their token
explicitly: mathieudutour/github-tag-action receives github_token: as a step input,
and make release (which runs goreleaser) receives GITHUB_TOKEN as an env var.
The git fetch --tags step is read-only on a public repository; a comment was added
to document this assumption. See manual-review.md for 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): 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 the dependabot.yml cooldown.
  • .github/workflows/zizmor.yaml: add persona: pedantic to the zizmor-action
    step. Extend paths: triggers to include .github/dependabot.yml and
    .github/zizmor.yml so changes to those files trigger the zizmor check.
  • .github/workflows/actionlint.yaml: extend paths: triggers to include
    .github/dependabot.yml and .github/zizmor.yml.
  • .github/dependabot.yml: add cooldown: default-days: 3 to both the gomod and
    github-actions package ecosystems, satisfying the dependabot-cooldown zizmor rule.

0004 — fix(ci): address actionlint and shellcheck findings

Fixes mechanical actionlint/shellcheck findings.

Changes:

  • .actionlint.yaml (new file): registers ubuntu-latest-8-core as a known custom
    runner label, suppressing the false-positive runner-label warning that appeared for
    melange-test-pipelines.yaml and wolfi-presubmit.yaml.
  • release.yaml: quote $GITHUB_OUTPUT in redirect operators (SC2086). Four
    occurrences of >> $GITHUB_OUTPUT corrected to >> "$GITHUB_OUTPUT" in the
    "Check if any changes since last release" step.
  • wolfi-presubmit.yaml: quote $(pwd) in docker run -v arguments (SC2046). All
    four 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-mismatch zizmor findings by annotating SHA-pinned action refs
with their corresponding version tag or branch name (looked up via the GitHub API).


Findings Not Patched

Finding Count Disposition
cache-poisoning 2 Manual review — see manual-review.md
unpinned-images 1 Manual review — alpine:latest requires SHA lookup
ref-version-mismatch 1 Fixed in patch 0005
stale-action-refs 1 Manual review — requires online check
concurrency-limits 9 Suppressed in zizmor.yml (low security value)
anonymous-definition 1 Suppressed in zizmor.yml (cosmetic, no security impact)
undocumented-permissions 1 Suppressed in zizmor.yml (style only)

References

Refs: PSEC-923

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
@stevebeattie stevebeattie requested review from antitree and egibs May 5, 2026 04:18
@egibs egibs merged commit 04312dd into main May 5, 2026
65 of 68 checks passed
@egibs egibs deleted the security/psec-923-melange branch May 5, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants