Join our Newsletter — 33% off our NHI Course

Why do GitHub Actions supply chain attacks keep exposing secrets even when teams pin SHAs?

Because SHA pinning only constrains what code is fetched, not what that code does once it runs. A malicious action, package, or injected workflow step can still access environment variables, read process memory, and print or send credentials from inside the runner. The risk is execution, not just provenance.

Why SHA pinning does not stop secret exposure in GitHub Actions

Pinning an action to a commit SHA improves integrity of what you fetch, but it does not sandbox what the code can do after checkout. If that action runs in a privileged workflow context, it can still read environment variables, access files and memory, and exfiltrate credentials that the runner can see. The attack succeeds at execution time, not just provenance time.

A useful way to think about this is that the supply chain control answers “what binary or script did we obtain?”, while the workflow runtime answers “what authority did we hand it once it started?”. A pinned SHA blocks tag drift and some forms of unexpected update, but it does not prevent a compromised action from abusing the job’s runtime permissions, inherited secrets, or other accessible material.

This is why attackers often prefer poisoning trusted actions, workflow steps, or transitive dependencies rather than replacing the whole repository. Once malicious code is executing inside the runner, the boundary that matters is the one around permissions and secret exposure, not the Git reference used to fetch the code. For a broader view of how action compromise turns into secret theft, see tj-actions/changed-files compromise 2025 and reviewdog Action compromise 2025.

Why secrets still leak from a pinned workflow

Secrets leak when the workflow grants them to code that does not actually need them, or when the runner already has access to material that should never reach untrusted logic. Even if the action itself is immutable, a malicious commit can still print, forward, or stage those values elsewhere. Environment variables, job outputs, cached files, artifact contents, and process state are all common leak paths.

The deeper issue is that many pipeline designs treat SHA pinning as a complete trust control when it is only one layer. A repository may pin an action and still expose long-lived tokens, broad-scoped repository secrets, or cloud credentials to every step in the job. That means compromise of one trusted dependency can convert into credential theft, repository access, package publishing abuse, or follow-on lateral movement.

Teams also underestimate how often secrets are available indirectly. A step may not be passed a secret explicitly, yet it can still inherit it through the runner environment, helper processes, mounted files, build tooling, or poorly isolated composite actions. That is why secret minimisation and execution isolation matter as much as source integrity.

What actually needs to be controlled

SHA pinning should be treated as a provenance control, not a privilege control. The practical question is whether the action, step, or dependency is given the minimum runtime authority needed to complete its task. If the answer is no, a pinned SHA only makes a malicious payload more repeatable.

In GitHub Actions, the safest pattern is to combine pinned references with narrow job permissions, least-privilege secrets, short-lived credentials, and workflow separation for untrusted input. That way, even if code execution is hijacked, the blast radius is limited. The goal is not to trust code because it is pinned, but to reduce what a compromised step can observe or use.

For implementation guidance on reducing secret exposure and moving away from static credentials, the Secret Sprawl Challenge, static vs dynamic secrets, and Secrets Management Guide all reinforce the same practical point: exposed credentials are a runtime problem first, and a provenance problem second.

Risk and Threat Considerations

Pinned SHAs can create a false sense of security because they lower supply-chain drift without removing the attacker’s ability to exploit the workflow at execution time. If a trusted action is compromised, or if a malicious step is injected into a job that already has broad secrets, the result is immediate credential exposure from within an apparently legitimate runner.

Failure mechanism: the attacker gets code execution in the workflow context, then uses that context to read secrets, environment variables, cache contents, logs, or reachable services before exfiltrating them.

Impact: stolen CI/CD secrets can be reused to publish malicious releases, access cloud resources, modify repositories, or launch follow-on supply chain attacks from trusted infrastructure.

Standards & Framework Alignment

This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.

OWASP Non-Human Identity Top 10 addresses the attack and risk surface, while NIST SP 800-53 Rev 5 sets the governance and control requirements practitioners need to meet.

Framework Control / Reference Relevance
OWASP Non-Human Identity Top 10 NHI-02 — Secret Leakage Pinned workflows still leak secrets through runtime execution paths.
NHI-05 — Overprivileged NHI Broad workflow permissions amplify the impact of a compromised action.
NHI-07 — Long-Lived Secrets Static credentials in CI/CD raise the blast radius when an action is compromised.
Recommendation — Limit secret exposure in workflows and rotate any credential reachable by runner execution. Reduce workflow and token privilege to the minimum required for each job. Replace long-lived CI/CD secrets with short-lived credentials wherever possible.
NIST SP 800-53 Rev 5 IA-5 — Authenticator Management CI/CD secret lifecycle and rotation are central to limiting stolen workflow credentials.
AC-6 — Least Privilege Workflow jobs need minimum access so compromised steps cannot abuse broad permissions.
Recommendation — Rotate and expire workflow credentials quickly and revoke exposed authenticators immediately. Scope each workflow job to the minimum permissions and secrets it needs.

Practitioner Guidance

What to prioritise: treat any workflow step that can access production credentials as a high-value execution point, even when the action is SHA-pinned. The first question is not whether the reference is immutable, it is whether that job can touch secrets, cloud tokens, or publishing rights.

What to verify: confirm that each job has only the permissions and secrets it truly needs, that untrusted pull request paths cannot inherit privileged credentials, and that secrets are short-lived where possible. If a step can reach a production system, assume a compromised action can reach it too.

Common mistake: teams pin dependencies and then leave broad repository secrets, write tokens, or cloud credentials available to the whole runner. That combination preserves provenance while keeping the blast radius wide open.

Practitioner takeaway: pinning is necessary, but it is not a secret-protection control. The decisive control is whether a compromised workflow step can actually see, use, or export anything worth stealing.