fix: remove GitHub Actions script injection in debug_info step (CWE-94) - #229
Merged
Conversation
The `debug_info` "Print github context JSON" step interpolated
`${{ toJson(github) }}` directly into a `run:` shell heredoc in four
reusable workflows. GitHub Actions substitutes `${{ }}` into the script
before the shell runs, so attacker-controllable event fields (e.g. a
commit message containing an `EOF` line plus shell commands) could break
out of the heredoc and execute arbitrary commands on the runner.
Pass the context through an `env:` variable and print it with
`echo "$GITHUB_CONTEXT"` so it is treated as data, mirroring the existing
safe `COMMIT_MESSAGE` pattern in create-release.yaml.
Also add a report-only zizmor self-scan to validate-workflows.yaml so this
class of issue is surfaced in the Security tab going forward (CodeQL did
not catch it). It is non-blocking (continue-on-error) and does not gate on
the repo's pre-existing findings.
Reported via giantswarm/giantswarm#36940.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
mproffitt
approved these changes
Jun 24, 2026
ljakimczuk
approved these changes
Jun 24, 2026
stone-z
reviewed
Jun 24, 2026
Comment on lines
+58
to
+79
| analyze-actions: | ||
| name: Analyze workflows with zizmor (report-only) | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read | ||
| security-events: write # upload SARIF to the Security tab (code scanning is enabled) | ||
| actions: read | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| # Report-only: zizmor uploads findings to the Security tab for visibility but never | ||
| # blocks PRs. The repo carries pre-existing findings that are tracked separately; this | ||
| # scan is here to surface regressions (e.g. re-introducing `${{ toJson(github) }}` in a | ||
| # `run:` block) that CodeQL did not catch. See giantswarm/giantswarm#36940. | ||
| - name: Run zizmor (non-blocking) | ||
| continue-on-error: true | ||
| uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7 | ||
| with: | ||
| persona: regular |
Contributor
There was a problem hiding this comment.
fyi @giantswarm/team-honeybadger zizmor is already available as a devctl-managed workflow https://github.com/giantswarm/devctl/blob/main/pkg/gen/input/workflows/internal/file/zizmor_base.yml.template
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.
What
Fixes a GitHub Actions script injection (CWE-94) in the
debug_info"Print github context JSON" step of four reusable workflows, and adds a report-onlyzizmorself-scan as a regression guardrail.Reported in giantswarm/giantswarm#36940 (severity 8.8 High, confirmed with a working PoC).
The vulnerability
The step interpolated
${{ toJson(github) }}directly into arun:shell heredoc:GitHub Actions performs literal text substitution of
${{ }}into the script before the shell runs it.toJson(github)embeds attacker-controllable fields (commit messages, PR titles/bodies, author name/email). A crafted commit message containing anEOFline followed by shell commands breaks out of the heredoc and runs arbitrary commands on the runner. Realistic vector: a maintainer squash-merging an external PR without editing the auto-populated commit message.The fix
Pass the context through an
env:variable so the shell treats it as data, not script text — the same safe pattern already used forCOMMIT_MESSAGEincreate-release.yaml:Applied identically to:
create-release.yamlcreate-release-pr.yamlupdate-chart.yamlensure-major-version-tags.yamlGuardrail (report-only)
CodeQL was enabled on this repo but did not catch this. This PR adds a non-blocking
zizmorself-scan job tovalidate-workflows.yaml(continue-on-error: true) that uploads findings to the Security tab. It does not gate PRs on the repo's pre-existing findings; it exists to surface regressions of this class.Verification
zizmorbefore → after: Hightemplate-injectionfindings dropped 31 → 27 — exactly the fourtoJson(github)sinks are gone.cat <<EOFheredocs remain in any workflow; alltoJson(github)now sit underenv:.persist-credentials: false, so it introduces no new findings.Out of scope (follow-up)
zizmorsurfaced ~180 pre-existing findings: other Hightemplate-injectionsites (branch names / inputs /github.actorinrun:blocks), 21artipackedcheckouts missingpersist-credentials: false, 7github-app, 1unpinned-uses. These are lower-severity than the merged-commit-message vector and touch working release machinery — to be addressed as a separate hardening effort. The report-only scan keeps them visible in the Security tab.🤖 Generated with Claude Code