Skip to content

Build Not yet confirmed elsewhere1 publisher 2 min read Published

The runner holds your deploy keys, and nobody put it in the scanning program

Codecov in 2021 and tj-actions/changed-files in March 2025 failed the same way: trusted third-party code running with pipeline privileges on a push nobody on your team made.

The Engineer · Build desk

Send a correction

What happened

  • The CI runner holds deploy keys, registry credentials, cloud tokens and signing secrets, and runs with more privilege than any developer, while going unreviewed on most projects.
  • The 2021 Codecov bash uploader compromise exposed secrets from thousands of CI environments.
  • In March 2025, tj-actions/changed-files was compromised and leaked secrets into build logs of every repository that referenced it by tag.
  • The writeup names pull_request_target combined with checking out the pull request head as the most reliable way to leak credentials from a public repository.

Why it matters

  • Who's exposed exposure Every action referenced by tag hands a third party a standing right to change what your next build executes, with no review event on your side to catch it.
  • Who has to decide decision Anyone needing privileged work on fork contributions now has to pick: split into an unprivileged build and a privileged artifact consumer, or keep carrying a known credential leak.
  • What it costs cost Older repositories left on default token permissions pay for a single compromised step with rewritable history and releases signed as CI.

The mechanism in both incidents is dull, which is part of why it keeps working. Trusted third-party code, running with pipeline privileges, on somebody else's push [4]. Roughly four years separate the Codecov bash uploader compromise from the tj-actions/changed-files compromise [19], and the referencing pattern that made the second one possible is still the default way workflow files name what they run.

That pattern is the tag. `uses: some-org/some-action@v3` resolves through a pointer that the upstream repository owner controls, so a compromised upstream account turns `v3` into attacker code on your next run with no change and no approval on your side [5]. A full commit SHA cannot be repointed [6]. The inventory of your exposure to this is one command: `grep -rn "uses:.*@v" .github/workflows/` [7]. Whatever else is true about supply chain security, the cost of finding out is not the obstacle here. The dev.to author's own expectation is that the count comes back worse than people guess [20].

The privilege arithmetic is where this gets expensive. Repository-wide secrets are readable by every workflow in the repository, including the lint job and including a job that runs a third-party formatter against a fork's pull request [8]. So the least-reviewed job in the repo carries the same read access as the deploy job, and the deploy key's blast radius is set by the sloppiest YAML file rather than the most careful one. The proposed test is a good one because it is falsifiable: for each secret, name the single job that needs it, and treat anything you cannot assign as over-shared [17]. Same logic on the token. A workflow with no `permissions:` block runs on the repository default, and on older repositories that default is write, which means a compromised step can push commits, edit releases or open pull requests wearing your CI's identity [12].

The failure that ties it together is detection. Log masking matches exact strings, so a secret that has been base64 encoded, JSON wrapped, or split across a variable expansion goes through unmasked [14], and on a public repository the logs are public and the artifacts are downloadable [15]. That is the tj-actions shape exactly: the leak arrived in build logs of every repository that referenced the action by tag [3].

One caveat on the evidence. This is a single practitioner writeup, and it offers no measurement of how many repositories are still tag-pinned or still running on default token permissions. The two named compromises are load-bearing; the prevalence is asserted, not counted.

What to watch

  • Whether any platform vendor makes SHA pinning or read-only default token permissions the enforced default rather than a documented recommendation.
  • Whether a measured survey appears showing what share of public repositories still reference third-party actions by tag.
  • The next action compromise, and whether the leak path is again build logs and downloadable artifacts on public repositories.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence52
Adoption24
Hype gap+18
Incentives34
Confidence55
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    A CI pipeline holds deploy keys, registry credentials, cloud tokens and signing secrets, runs on every push, runs third-party code the team did not write, and runs with more privilege than any developer on the team; for most projects it is completely unreviewed.

    Reported Supported Source: dev.to writeup by lucky3mcView cited source
  2. [2]

    The Codecov bash uploader compromise in 2021 exposed secrets from thousands of CI environments.

    Reported SupportedView cited source
  3. [3]

    In March 2025 the widely used tj-actions/changed-files action was compromised and began leaking secrets into the build logs of every repository that referenced it by tag.

    Reported SupportedView cited source

Get this ledger inside ChatGPT. Ask about any of our stories and the answer brings its figure, each claim’s verdict and the sources. Free, no account.

Add to ChatGPTAdd to Claude

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · August 21, 2026

    Your CI Pipeline Is the Most Privileged Machine You Own. You Have Never Scanned It.

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

Loading related stories