Skip to content

fix(ci): pin GitHub Actions to commit SHAs (supply chain hardening)#1322

Merged
ErikBjare merged 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/pin-action-shas
Jun 19, 2026
Merged

fix(ci): pin GitHub Actions to commit SHAs (supply chain hardening)#1322
ErikBjare merged 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/pin-action-shas

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Summary

All 10 external action references in the CI workflows were using mutable tags or branch names. A tag or branch is a movable pointer — whoever controls the upstream action repository (or anyone who compromises it) can re-point it, and the next workflow run executes the new code with the job's token and any available secrets.

This was flagged by Thibaud Van Den Berghe (thibaud@getplumber.io), who identified the pattern by running the Plumber CLI against the repo. The same attack vector was exploited in CVE-2025-30066 (tj-actions/changed-files), where a moved tag caused CI secrets to be dumped in every consuming repository on the next run.

Changes

Each third-party action is now pinned to its current commit SHA with the human-readable version in a comment:

File Action Was Now
release.yml (×2) dtolnay/rust-toolchain @master @3c5f7ea
release.yml (×2) nick-fields/retry @v4 @ad984534
release.yml softprops/action-gh-release @v3 @b4309332
release.yml (×2) ActivityWatch/check-version-format-action @v2 @5b223bd (v2.0.1)
diagram.yml githubocto/repo-visualizer @main @a999615
dependabot-automerge.yml ridedott/merge-me-action @v2 @e45e8ab
winget.yml vedantmgoyal2009/winget-releaser @v2 @4ffc7888

The priority targets (dtolnay/rust-toolchain@master and softprops/action-gh-release@v3) were in the release pipeline and had access to publishing credentials. githubocto/repo-visualizer@main had contents: write on a moving branch.

github/codeql-action (GitHub-maintained) is left for a separate pass — it's lower risk than third-party actions.

Keeping SHAs current

To avoid SHA rot, consider adding Renovate or pinact to keep these pinned references updated automatically when upstream releases new versions.

All 10 external action references were using mutable tags or branches.
Pin each third-party action to its current commit SHA with the version
in a comment, following the tj-actions/changed-files incident pattern
(CVE-2025-30066).

Pinned actions:
- dtolnay/rust-toolchain@master -> @3c5f7ea (release.yml, 2x)
- nick-fields/retry@v4 -> @ad984534 (release.yml, 2x)
- softprops/action-gh-release@v3 -> @b4309332 (release.yml)
- ActivityWatch/check-version-format-action@v2 -> @5b223bd (release.yml, 2x)
- githubocto/repo-visualizer@main -> @a999615 (diagram.yml)
- ridedott/merge-me-action@v2 -> @e45e8ab (dependabot-automerge.yml)
- vedantmgoyal2009/winget-releaser@v2 -> @4ffc7888 (winget.yml)

github/codeql-action (GitHub-maintained) left for a separate pass.
Use pinact or Renovate to keep SHAs updated going forward.
@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Replaces all 10 mutable tag/branch references for third-party GitHub Actions with full 40-character commit SHAs and human-readable version comments, closing the supply-chain attack vector where a compromised upstream tag could silently inject code into CI runs that have access to release credentials and secrets.

  • release.yml – Pins dtolnay/rust-toolchain (×2), nick-fields/retry (×2), softprops/action-gh-release, and ActivityWatch/check-version-format-action (×2); these jobs have contents: write and access to signing/publishing secrets, making them the highest-priority targets.
  • diagram.yml / dependabot-automerge.yml / winget.yml – Pins the remaining three third-party actions used in auxiliary workflows; first-party GitHub-maintained actions are deliberately deferred to a follow-up pass, as noted in the PR description.

Confidence Score: 5/5

Safe to merge — the changes are purely additive SHA pins on mutable tags with no logic modifications.

Every change is a mechanical substitution of a mutable tag or branch reference for its corresponding full 40-character commit SHA plus a version comment. No workflow logic, permissions, secrets usage, or job ordering is touched. The scope is well-defined and the PR description accounts for the intentional omission of first-party GitHub-managed actions.

No files require special attention. All four workflow files receive straightforward SHA substitutions.

Important Files Changed

Filename Overview
.github/workflows/release.yml Pins dtolnay/rust-toolchain (×2), nick-fields/retry (×2), softprops/action-gh-release, and ActivityWatch/check-version-format-action (×2) to full 40-char commit SHAs; first-party actions remain on mutable version tags, intentionally deferred per the PR description.
.github/workflows/dependabot-automerge.yml Pins ridedott/merge-me-action to a full commit SHA; workflow logic and PAT usage are unchanged.
.github/workflows/diagram.yml Pins githubocto/repo-visualizer to a full commit SHA; workflow only triggers on the diagram branch or manual dispatch, limiting blast radius.
.github/workflows/winget.yml Pins vedantmgoyal2009/winget-releaser to a full commit SHA; no other changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph release_yml["release.yml (contents: write + secrets)"]
        R1["dtolnay/rust-toolchain\n@3c5f7ea... pinned (was @master)"]
        R2["nick-fields/retry\n@ad984534... pinned (was @v4)"]
        R3["ActivityWatch/check-version-format-action\n@5b223bd7... pinned (was @v2)"]
        R4["softprops/action-gh-release\n@b4309332... pinned (was @v3)"]
    end
    subgraph diagram_yml["diagram.yml (contents: write on diagram branch)"]
        D1["githubocto/repo-visualizer\n@a999615b... pinned (was @main)"]
    end
    subgraph auto_yml["dependabot-automerge.yml (contents: write)"]
        A1["ridedott/merge-me-action\n@e45e8ab1... pinned (was @v2)"]
    end
    subgraph winget_yml["winget.yml"]
        W1["vedantmgoyal2009/winget-releaser\n@4ffc7888... pinned (was @v2)"]
    end
    subgraph unpinned["First-party actions — deferred"]
        U1["actions/checkout@v6"]
        U2["actions/setup-python@v6"]
        U3["actions/cache@v5"]
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph release_yml["release.yml (contents: write + secrets)"]
        R1["dtolnay/rust-toolchain\n@3c5f7ea... pinned (was @master)"]
        R2["nick-fields/retry\n@ad984534... pinned (was @v4)"]
        R3["ActivityWatch/check-version-format-action\n@5b223bd7... pinned (was @v2)"]
        R4["softprops/action-gh-release\n@b4309332... pinned (was @v3)"]
    end
    subgraph diagram_yml["diagram.yml (contents: write on diagram branch)"]
        D1["githubocto/repo-visualizer\n@a999615b... pinned (was @main)"]
    end
    subgraph auto_yml["dependabot-automerge.yml (contents: write)"]
        A1["ridedott/merge-me-action\n@e45e8ab1... pinned (was @v2)"]
    end
    subgraph winget_yml["winget.yml"]
        W1["vedantmgoyal2009/winget-releaser\n@4ffc7888... pinned (was @v2)"]
    end
    subgraph unpinned["First-party actions — deferred"]
        U1["actions/checkout@v6"]
        U2["actions/setup-python@v6"]
        U3["actions/cache@v5"]
    end
Loading

Reviews (1): Last reviewed commit: "fix(ci): pin GitHub Actions to commit SH..." | Re-trigger Greptile

@ErikBjare ErikBjare merged commit b2cd444 into ActivityWatch:master Jun 19, 2026
15 checks passed
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