TL;DR: Deleted or disabled GitHub Actions workflows can still be triggered through certain pull request paths, according to Sonar’s analysis, creating a hidden attack surface that can execute arbitrary code in runner environments and expose repository secrets. The risk is not just a workflow bug but a CI/CD governance gap that leaves privileged automation, and the identities behind it, outside lifecycle control.
At a glance
What this is: Sonar shows that zombie workflows in GitHub Actions can remain triggerable after deletion or disablement, creating a hidden CI/CD attack path into runner execution and secrets.
Why it matters: This matters because identity and access controls in CI/CD do not end at the active branch; stale workflow versions can keep privileged automation reachable unless lifecycle governance is explicit.
By the numbers:
- Sonar found 188 vulnerable workflows during its large-scale triage, before narrowing them to 67 true Zombie Workflows.
Context
Zombie workflows are a CI/CD governance problem in which older workflow definitions remain reachable even after teams think they have removed them. In GitHub Actions, that means the effective security boundary is not just the current default branch, but the set of historical workflow versions still reachable through pull request execution paths.
The identity angle is real because these workflows often run with repository tokens, secrets, and write permissions that function like machine identities in practice. When workflow lifecycle and branch lifecycle diverge, teams can lose control of who or what is still authorised to execute privileged automation.
Key questions
Q: What breaks when a GitHub Actions workflow is fixed in only one branch?
A: The fix is incomplete because attackers may still trigger a vulnerable workflow version from another branch or historical state. That leaves privileged automation exposed even though the default branch looks safe. Teams need branch-wide remediation, not a single-file patch, because workflow execution can follow branch resolution rules that preserve old attack paths.
Q: Why do pull_request_target workflows create more risk than standard pull request workflows?
A: pull_request_target runs in the base repository context, which can expose secrets and write-enabled tokens to code that came from a fork. That makes it suitable for metadata tasks, but risky for any workflow that executes contributor-controlled code or checks out the pull request head.
Q: How can teams tell whether zombie workflow risk is still present?
A: Look for any workflow that can still be triggered from branches other than the default branch, especially if it uses pull_request_target, checks out PR code, or accesses secrets. A workflow is still risky if a retired or patched version remains executable somewhere in branch history. The observable signal is reachability, not whether the main branch looks clean.
Q: What should security teams do when a privileged workflow is discovered in branch history?
A: Treat it as a lingering access path and verify whether it can still be selected by a pull request against any live branch. If it can, revoke the automation path by updating every branch that can execute the workflow and removing unnecessary secrets or write permissions. Containment starts with cutting off reachability, not just editing the current file.
Technical breakdown
How GitHub Actions resolves workflow versions on pull requests
GitHub Actions decides three things separately when a pull request triggers a workflow: which branch state to treat as the base, which workflow file to run, and which code to check out. The safe default is to run the workflow file from the base branch, because that file is already in the trusted repository history. The problem appears when teams intentionally override checkout to test PR changes. That can create a gap between the workflow definition and the code being executed, especially if an older workflow version remains reachable in another branch.
Practical implication: Treat workflow source and checkout source as separate trust decisions, and review both whenever pull request automation is enabled.
Why pull_request_target creates a privileged execution path
The pull_request_target event runs in the context of the target repository rather than the contributor’s fork, which makes it useful but dangerous. If a workflow uses pull request content unsafely while retaining write permissions or secrets, an attacker can turn repository changes into code execution inside the runner environment. That is the classic Pwn Request pattern. Zombie workflows extend that risk by allowing a previously fixed or disabled workflow version to remain reachable through branch selection and historical branch state.
Practical implication: Limit pull_request_target to narrowly reviewed cases, and separate untrusted code handling from any step that can access secrets or write permissions.
Zombie workflows as a lifecycle control failure
A zombie workflow exists when a workflow that appears retired is still triggerable because another branch retains an exploitable version. This is not a normal vulnerability in one file alone; it is a lifecycle control failure across branch management, workflow promotion, and privilege scope. In governance terms, the organisation has not fully revoked the automation path, even if the current main branch looks fixed. That makes stale branches a standing access surface for CI/CD compromise.
Practical implication: Inventory all branches that can still host executable workflow definitions and treat workflow retirement as a multi-branch revocation problem.
Threat narrative
Attacker objective: The attacker wants privileged code execution in CI/CD so they can steal secrets, tamper with build logic, or use the pipeline as a supply chain foothold.
- Entry occurs when an attacker gains write influence over a repository branch or opens a pull request against a branch that still contains a vulnerable workflow version.
- Credential access follows when the workflow runs with repository secrets, write permissions, or a privileged GITHUB_TOKEN inside the runner environment.
- Impact occurs when the attacker executes arbitrary code in the GitHub Actions runner and can expose secrets or alter repository state.
Breaches seen in the wild
- tj-actions/changed-files compromise 2025: A stolen bot token let attackers poison tj-actions/changed-files so pipelines printed their CI/CD secrets to public logs (CVE-2025-30066).
- reviewdog Action compromise 2025: A stolen maintainer token poisoned reviewdog/action-setup, leaking CI secrets including the tj-actions bot token used in the next attack.
Read and download The State of NHI & AI Agent Breach Report 2026, covering 200+ breaches impacting Non-Human Identities including AI Agents.
NHI Mgmt Group analysis
Zombie workflows are a lifecycle revocation failure, not a simple misconfiguration. The real issue is that teams can fix one branch while leaving other executable branch states alive. That creates a privilege residue problem in CI/CD, where retired automation still carries access. Practitioners should treat workflow retirement as revocation across every branch that can still execute code.
CI/CD pipelines now behave like machine identity estates, and they need lifecycle control. Secrets, write tokens, and runner permissions are effectively non-human identities in motion. If those identities can still be invoked through historical workflow versions, the governance model has failed at inventory and offboarding. The field should stop treating workflow files as static artifacts and start governing them as access-bearing assets.
Hidden branch history is an attack surface in its own right. The article’s scale numbers show how common this problem can become when teams only patch the default branch. That is a strong signal that branch hygiene, release branching, and workflow promotion are security controls, not just engineering practices. Security teams should fold branch exposure into CI/CD risk reviews and incident assumptions.
Zombie workflow exposure sharpens the case for path-based CI/CD trust controls. Not every pull request should inherit the same privileges, and not every branch should remain able to trigger the same automation. This is where the identity bridge matters: access scope in CI/CD is tied to both the repository state and the workflow state. Practitioners should make that relationship explicit in governance and review it continuously.
Branch-scoped automation creates a governance gap unless default and non-default branches are held to the same control standard. The article shows that a fix on the default branch can leave older paths exploitable, which means security assurance has to extend beyond the mainline. For practitioners, the lesson is straightforward: if a workflow can still execute, it is still part of the trusted perimeter.
From our research library:
- 96% of organisations store secrets outside of secrets managers in vulnerable locations including code, config files, and CI/CD tools, according to the Ultimate Guide to NHIs.
- Read next: CI/CD Pipeline Identity Security Guide
What this signals
Zombie workflow exposure is a release-management problem as much as a GitHub Actions problem. The Sonar findings show that once a privileged workflow version survives somewhere in branch history, fix velocity on the default branch is not enough. Security teams should expect CI/CD review to become branch-aware, because automation that can still run is still part of the attack surface. The article’s triage numbers underline that this is not a corner case: Sonar found 188 vulnerable workflows before narrowing them to 67 true Zombie Workflows.
Sonar’s analysis also points to a broader lesson for governance: machine identity in pipelines is only as controlled as the lifecycle of the workflow that carries it. When repository secrets and write tokens remain reachable through historical workflow states, lifecycle control has failed even if the current main branch appears clean. Teams should align CI/CD governance with branch management, secret scope, and runner trust boundaries.
Branch-scoped automation debt: stale workflow versions create a hidden access layer that outlives the fix. That should change how practitioners think about pull_request_target, especially in repositories where contributor-controlled code can influence runner behaviour. A workflow is not secure simply because it is disabled on one branch; it must be unreachable everywhere that still matters.
For practitioners
- Audit every executable branch for stale workflows Map all branches that can still trigger GitHub Actions, not just default branch content, and flag any workflow file that remains runnable after a fix. Focus on release, hotfix, and long-lived feature branches.
- Reduce privileged pull request automation Replace broad pull_request_target usage with the least privileged trigger that still supports the workflow, and separate untrusted PR code from any step that can read secrets or write to the repository.
- Treat workflow retirement as revocation When a workflow is fixed or removed, verify that the change is not stranded in older branches and that historical versions cannot still be selected by a pull request path.
- Constrain runner-side secret exposure Minimise repository secrets and privileged tokens in any workflow that checks out contributor-controlled code, because arbitrary runner execution becomes a secret exposure event once code paths are unsafe.
Key takeaways
- Zombie workflows show that CI/CD privilege can persist in branch history even after teams believe a workflow has been removed or fixed.
- The attack matters because runner execution, repository secrets, and write tokens turn stale automation into an exploitable access path.
- The practical control gap is lifecycle governance across every executable branch, not just patching the current default branch.
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 and MITRE ATT&CK address the attack and risk surface, while CIS Controls v8 sets the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| OWASP Non-Human Identity Top 10 | NHI-02 — Secret Leakage | Stale workflows can expose repository secrets and privileged tokens through runner execution. |
| NHI-05 — Overprivileged NHI | Pull request workflows often retain more access than the task requires. | |
| NHI-07 — Long-Lived Secrets | Branch history can keep old secret-bearing workflows reachable long after they should be retired. | |
| Recommendation — Scan CI/CD workflows for secret exposure paths and revoke any workflow that can still reach sensitive values. Reduce workflow permissions to the minimum required for each branch and event. Rotate and revoke workflow secrets whenever a privileged automation path is retired or repurposed. | ||
| MITRE ATT&CK | TA0006; TA0008 — Credential Access; Lateral Movement | The abuse path uses workflow execution to reach secrets and move into repository control. |
| Recommendation — Map CI/CD abuse paths to credential access and lateral movement to prioritise detections on workflow-triggered token use. | ||
| CIS Controls v8 | CIS-5 — Account Management | Workflow and token lifecycle management is an account governance problem in CI/CD. |
| Recommendation — Track workflow-triggered tokens and permissions as managed accounts that must be removed when no longer needed. | ||
Key terms
- Zombie Workflow: A zombie workflow is a pipeline definition that appears fixed, deleted, or disabled but can still be triggered through a branch, event, or historical resolution path. The term describes a governance failure where the old privileged behavior remains available even though the team believes the workflow is no longer active.
- Pull_request_target workflow: A GitHub Actions trigger that runs in the context of the base repository, not the contributor’s fork. That means it can access repository secrets while processing untrusted pull request content, which creates a sharp trust boundary and a common route to secret theft if not carefully segmented.
- Pwn Request: A pull request or related contribution flow that can execute attacker-controlled content in a privileged build context. The risk appears when workflow design lets untrusted input reach shell commands, secrets, or release tooling without a clean trust boundary.
- Branch-scoped automation: Branch-scoped automation is workflow execution that varies by branch state, branch history, or branch selection. It becomes a governance issue when older branches still carry executable privileges that the organisation assumes were removed from the current default branch.
Deepen your knowledge
The NHI Foundation Level course covers NHI governance, machine identity security, and secrets management, giving practitioners a structured way to govern access-bearing automation. It is built for teams that need to connect identity controls to real operational risk across pipelines and workloads.
Published by the NHIMG editorial team on August 20, 2026.
Updated on October 12, 2026.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org