Security: Pin GitHub Actions to immutable SHA hashes#27135
Security: Pin GitHub Actions to immutable SHA hashes#27135brendandburns wants to merge 5 commits intoPowerShell:masterfrom
Conversation
- Update all GitHub Action references from mutable tags to immutable SHA hashes - Prevents supply chain attacks via tag hijacking and force-pushing - Addresses security vulnerabilities similar to the LiteLLM incident with Trivy - Maintains version comments for clarity while ensuring cryptographic immutability - Affects 38 action references across 9 workflow files Actions updated: - actions/checkout@v6 → @1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - actions/setup-dotnet@v5 → @d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0 - actions/upload-artifact@v7 → @bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - actions/github-script@v8 → @ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - PowerShell/compliance/...@v1.0.0 → @c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0
There was a problem hiding this comment.
Pull request overview
This PR primarily hardens CI/CD supply-chain security by pinning GitHub Actions uses: references to immutable commit SHAs, replacing mutable version tags. It also includes an unrelated functional change to Write-Host’s object-to-string processing and corresponding test updates.
Changes:
- Pin third-party GitHub Actions (e.g.,
actions/checkout,actions/setup-dotnet,actions/upload-artifact,actions/github-script,github/codeql-action, andPowerShell/compliance) to immutable commit SHAs across workflows. - Update
Write-Hostruntime behavior to treatIDictionaryas a scalar (not anIEnumerableto be unrolled) and add a new test case validating the behavior.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteConsoleCmdlet.cs |
Updates Write-Host object processing to special-case IDictionary. |
test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Host.Tests.ps1 |
Adds a test case for IDictionary (Hashtable) output behavior. |
.github/workflows/analyze-reusable.yml |
Pins actions/setup-dotnet (and already has SHA pins for checkout/codeql). |
.github/workflows/copilot-setup-steps.yml |
Pins actions/checkout to an immutable SHA. |
.github/workflows/labels.yml |
Pins actions/checkout and actions/github-script to immutable SHAs. |
.github/workflows/linux-ci.yml |
Pins actions/checkout and PowerShell/compliance workflow reference to immutable SHAs. |
.github/workflows/macos-ci.yml |
Pins actions/checkout, actions/setup-dotnet, actions/upload-artifact, and PowerShell/compliance to immutable SHAs. |
.github/workflows/verify-markdown-links.yml |
Pins actions/checkout to an immutable SHA. |
.github/workflows/windows-ci.yml |
Pins actions/checkout and PowerShell/compliance workflow reference to immutable SHAs. |
.github/workflows/windows-packaging-reusable.yml |
Pins actions/checkout, actions/setup-dotnet, and actions/upload-artifact to immutable SHAs. |
.github/workflows/xunit-tests.yml |
Pins actions/checkout, actions/setup-dotnet, and actions/upload-artifact to immutable SHAs. |
| switch (o) | ||
| { | ||
| // strings are IEnumerable, so we special case them | ||
| if (s.Length > 0) | ||
| { | ||
| return s; | ||
| } | ||
| } | ||
| else if (o is XmlNode xmlNode) | ||
| { | ||
| return xmlNode.Name; | ||
| } | ||
| else if (o is IEnumerable enumerable) | ||
| { | ||
| // unroll enumerables, including arrays. | ||
|
|
||
| bool printSeparator = false; | ||
| StringBuilder result = new(); | ||
|
|
||
| foreach (object element in enumerable) | ||
| { | ||
| if (printSeparator && Separator != null) | ||
| case string s: | ||
| // strings are IEnumerable, so we special case them | ||
| if (s.Length > 0) | ||
| { | ||
| result.Append(Separator.ToString()); | ||
| return s; | ||
| } | ||
| break; | ||
| case XmlNode xmlNode: | ||
| return xmlNode.Name; | ||
| case IDictionary dictionary: | ||
| return dictionary.ToString(); | ||
| case IEnumerable enumerable: |
There was a problem hiding this comment.
The PR description/title focus on pinning GitHub Actions to immutable SHAs, but this hunk also changes Write-Host runtime behavior (adds an IDictionary special-case in ProcessObject). This functional change should either be moved to a separate PR (preferred) or the PR description updated to include the Write-Host behavior change and its rationale/compat considerations.
|
Whilst reviewing this & I can't speak for the team, I'd be more inclined to split out the changes around Write-Host to it's own PR, if they are still needed, to keep this PR just to the SHA Hash changes. It's also worth readers coming to this PR to also have a read of The Comforting Lie Of SHA Pinning which follows on from the linked hack & suggests there are still security concerns even with using SHA hashes for GitHub Actions that need to be considered which can be summed up by this quote from that article
Dependabot is configured on this repo & by looks of the last few PR's it has raised it is preferring use of SHA Commits - just seems that the actions being changed in this PR had been missed in moving across to using SHA commits over version tags. |
|
I agree that they should be separate. I've created a PR with the action pins and I'll see if I can merge. |
|
@brendandburns Can you update the title and description of your PR? |
Summary
This PR updates all GitHub Actions in our CI/CD workflows to use immutable commit SHA hashes instead of mutable tag references, significantly enhancing our supply chain security posture.
Security Impact
Problem: Mutable Tag Vulnerability
Mutable references like
@v6,@latest, or branch names can be force-pushed by attackers who compromise action repositories, allowing them to inject malicious code into our CI/CD pipeline without detection.Solution: Cryptographically Immutable SHA Hashes
SHA-256 commit hashes are cryptographically immutable and cannot be changed, preventing supply chain attacks.
Real-World Security Incident Reference
This change directly addresses vulnerabilities similar to the LiteLLM security incident where their CI/CD pipeline was compromised through their usage of Trivy with mutable tag references. When the Trivy action repository was compromised, attackers were able to modify what the mutable tags pointed to, injecting malicious code into LiteLLM's build process.
Reference: Trivy Security Advisory GHSA-69fq-xp46-6x23
Changes Made
Updated 38 action references across 9 workflow files:
actions/checkout@v6@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0actions/setup-dotnet@v5@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0actions/upload-artifact@v7@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0actions/github-script@v8@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0PowerShell/compliance/...ready-to-merge.yml@v1.0.0@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0Files Updated:
.github/workflows/analyze-reusable.yml.github/workflows/copilot-setup-steps.yml.github/workflows/labels.yml.github/workflows/linux-ci.yml.github/workflows/macos-ci.yml.github/workflows/verify-markdown-links.yml.github/workflows/windows-ci.yml.github/workflows/windows-packaging-reusable.yml.github/workflows/xunit-tests.ymlSecurity Benefits
✅ Supply Chain Protection: Prevents tag hijacking and malicious code injection
✅ Immutability: SHA hashes cannot be force-pushed or modified by attackers
✅ Transparency: Version comments maintain readability and audit trail
✅ Compliance: Aligns with GitHub security best practices
Verification
All SHA hashes have been verified against the official repositories and correspond to the intended version tags.
Recommended Follow-up
Consider enabling Dependabot for GitHub Actions to automatically update these SHA-pinned actions to newer versions while maintaining security.
Related
This change prevents supply chain attacks while maintaining full functionality of our CI/CD workflows.