Skip to content

fix: pin 1 unpinned action(s),extract 1 unsafe expression(s) to env vars#402

Closed
dagecko wants to merge 1 commit intopypa:unstable/v1from
dagecko:runner-guard/fix-ci-security
Closed

fix: pin 1 unpinned action(s),extract 1 unsafe expression(s) to env vars#402
dagecko wants to merge 1 commit intopypa:unstable/v1from
dagecko:runner-guard/fix-ci-security

Conversation

@dagecko
Copy link
Copy Markdown

@dagecko dagecko commented Apr 4, 2026

Summary

This PR hardens your CI/CD workflows against supply chain attacks by pinning a third-party GitHub Action to an immutable commit SHA and extracting a secret from a run: block into an env: mapping.

Why this matters

The build-and-push workflow references re-actors/alls-green@release/v1 on a mutable tag in a pipeline that has packages: write permission to your container registry.

Over the last 5 weeks I've been tracking a nation state actor targeting maintainers of high profile open source projects through social engineering campaigns designed to compromise their accounts. The attack pattern we've seen with tj-actions, Trivy, and Axios all followed the same vector: compromise a maintainer account, force-push malicious code to a mutable tag, and every downstream project silently executes the attacker's code.

If the re-actors/alls-green maintainer account were compromised, the attacker could replace what release/v1 points to. Their modified action would then execute in this workflow with write access to your package registry. Pinning to the commit SHA prevents this because a pinned hash cannot be moved even if the upstream account is compromised.

Fixes applied (in this PR)

Rule Severity File Description
RGS-007 medium build-and-push-docker-image.yml Pinned 1 action to commit SHA
RGS-008 high build-and-push-docker-image.yml Extracted secrets.GITHUB_TOKEN from docker login run block to env mapping

How to verify

Every change is mechanical and preserves workflow behavior:

  • SHA pinning: action@release/v1 becomes action@abc123 # release/v1 - original ref preserved as comment
  • Secret extraction: ${{ secrets.GITHUB_TOKEN }} moves from the run: block to an env: mapping, preventing shell interpretation
  • No workflow logic, triggers, or permissions are modified

I've had 29 merges so far. I created a tool called Runner Guard to assist in my research - it does mechanical, non-AI fixes to reduce hallucinations to zero and produce consistent fixes. If you would like to scan it yourself to validate my work, feel free.

Happy to answer any questions - I'm monitoring comms on every PR.

- Chris Nyhuis (dagecko)

Automated security fixes applied by Runner Guard (https://github.com/Vigilant-LLC/runner-guard).

Changes:
 .github/workflows/build-and-push-docker-image.yml | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # release/v1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not change this. Also, the convention is a double-space before a comment.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FTR, this is explicitly excluded from the checks in the tooling that we already use for security: https://github.com/pypa/gh-action-pypi-publish/blob/cef221092ed1bacb1cc03d23a2d87d1d172e277b/.github/zizmor.yml#L8C9-L8C29. It's a justified exception for deps that are trusted.

run: >-
echo ${{ secrets.GITHUB_TOKEN }} |
echo "${GITHUB_TOKEN}" |
docker login ghcr.io -u $GITHUB_ACTOR --password-stdin
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could become a --password then.

@webknjaz
Copy link
Copy Markdown
Member

webknjaz commented Apr 7, 2026

The build-and-push workflow references re-actors/alls-green@release/v1 on a mutable tag in a pipeline that has packages: write permission to your container registry.

  1. It's not a tag but a branch.
  2. I'm not concerned about hacking myself with my own action and it's easier to maintain such moving pointers. At least, until there's an acceptable mechanism for maintaining actions and reusable workflow deptree pinning is implemented.

@webknjaz webknjaz requested review from facutuesca and woodruffw April 7, 2026 10:46
- name: Log in to GHCR
run: >-
echo ${{ secrets.GITHUB_TOKEN }} |
echo "${GITHUB_TOKEN}" |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FTR, this is likely not vulnurable to https://docs.zizmor.sh/audits/#template-injection as this specific secret is built-in / special-cased rather than being injected by human actors.

@webknjaz webknjaz added the ai-slop Ansolicited LLM-generated interactions, no fact-checking, inauthentic activity, no project ctx. label Apr 7, 2026
@webknjaz
Copy link
Copy Markdown
Member

webknjaz commented Apr 7, 2026

Having checked the OP's activity (with multiple contributions to other projects w/o taking into account the context of each) and low usefulness of the patch to us, I'm going to just close it as slop.

@dagecko
Copy link
Copy Markdown
Author

dagecko commented Apr 8, 2026

Hey @webknjaz, I'd encourage you to look at the changes before assuming it's slop. The PR pins a mutable ref on an action with packages: write permission to your container registry and extracts secrets.GITHUB_TOKEN from a run block to an env mapping.

Feel free to close it if you're not interested, but you might want to check with some of the projects that did take a look. next.js, svelte, metabase, keras, webpack, lazygit, apache/superset, and others have all merged similar hardening PRs after reviewing them.

@woodruffw, commenting here as the GHSA was closed. I find it odd that you're saying this is a non-issue here when you submitted the same hash-pinning fix to python/cpython (gh-146489) 25 minutes after I submitted mine, and it was merged. You've also been submitting the same class of fix to:

The attack vector is the same across all of these. Account takeover leading to mutable ref poisoning. That's what happened with tj-actions, Trivy, and axios. The concern was never that a maintainer would attack their own action. The concern is that a compromised account can move a mutable ref, and every downstream consumer silently executes the attacker's code. Pinning to SHA is the only mitigation that survives that.

  • Chris

@webknjaz
Copy link
Copy Markdown
Member

webknjaz commented Apr 8, 2026

I find it odd that you're saying this is a non-issue here when you submitted the same hash-pinning fix to python/cpython (gh-146489) 25 minutes after I submitted mine, and it was merged.

Nothing odd here, William has a good reputation and is a well-known security tooling author and contributor in the ecosystem. He also followed the conventions and took into account the project context, adjusted the security tooling configuration and so on. OTOH, you didn't do any of that which is why it looks like typical spam (especially taking into account the repetitive activity on the account that hasn't improved over time), even if a thing or two happen to be relevant it's mostly by accident and not because you invested into not wasting maintainer time. This type of spam is not new — big projects get a lot of low-quality reports from uneducated newbies running various scanners all the time, with no understanding that every single thing they forward must've been questioned and checked within the project context before forwarding.

The concern is that a compromised account can move a mutable ref, and every downstream consumer silently executes the attacker's code.

Once you do your homework, you'll realize that both actions are mine and this is not a viable scenario within the accepted threat model.

@woodruffw
Copy link
Copy Markdown
Member

@woodruffw, commenting here as the GHSA was closed. I find it odd that you're saying this is a non-issue here when you submitted the same hash-pinning fix to python/cpython (gh-146489) 25 minutes after I submitted mine, and it was merged. You've also been submitting the same class of fix to:

I'll note that this PR is categorically not like your CPython PR -- as @webknjaz notes all you've done here is (1) hash-pin a dependency that's considered trusted by the project's threat model, and (2) fix a template injection that isn't even close to exploitable (in order for an attacker to inject code through secrets.GITHUB_TOKEN an attacker would need to mutate that value in the runner's agent's memory, at which point they already have full code execution).

Both of these are "informational" findings at the absolute best, and filing a high-severity GHSA was a noisy and inconsiderate thing to do. Please remember that the people who maintain these projects do it because they're passionate open source maintainers; they don't get compensated to do it, and throwing overstated findings at them makes it harder to convince them to do the security work that actually matters.

On the topic of the CPython and other PRs: if you look at my contribution history, you'll see that I've been filing fixes based on zizmor's findings for well over a year. Critically, I only file PRs against projects that I actually use or depend on, and every single one of my PRs is authored by an actual human being (me) to tailor it to the project's submission requirements. You can see that doing this isn't trivial; this is an example of what it takes to actually land those kind of changes here: python/cpython#146488. By contrast, you dumped a PR on CPython's maintainers that didn't follow any of their contribution requirements; that isn't going to get you the result you want.

If you adopt a more tailored posture (and accept that it comes with much more manual labor), then you'll find that projects act more receptively towards your changes. But until then, what you're doing is indistinguishable from spam (or worse, reputation farming/smurfing). It's harmful to the projects you seem to be genuinely interested in helping, so please consider another approach.

@pypa pypa locked as spam and limited conversation to collaborators Apr 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ai-slop Ansolicited LLM-generated interactions, no fact-checking, inauthentic activity, no project ctx.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants