GhostAction Operators Pivot From Workflow Injection to a Fake-Font Stealer
The threat actor behind GhostAction, a persistent GitHub supply chain campaign first identified in September 2025, has expanded its toolkit well beyond the malicious GitHub Actions workflows that made it notorious. Researchers at OpenSourceMalware have documented a new wave in which the group plants a credential-stealing script disguised as a font file across 94 GitHub repositories belonging to 66 owners, paired with a phishing operation that impersonates GitHub security alerts to hijack developer accounts via OAuth device-flow abuse. The pivot appears to be a direct response to GitHub's mitigation efforts that have been blocking the group's malicious workflows from executing.
The cluster was first spotted by Jamf Threat Labs researcher Thijs Xhaflaire while hunting infections tied to PolinRider, a separate stealer family whose technique GhostAction's operators appear to have copied wholesale.
Incident Details
| Attribute | Value |
|---|---|
| Threat Actor | GhostAction (unattributed, assessed as low-to-moderate skill) |
| First Observed | September 2025 (original wave); new font-stealer wave reported October 19, 2026 |
| Repositories Affected (new wave) | 94 (66 owners; payload confirmed in 79 of 79 accessible repos, 15 inaccessible) |
| Payload Disguise | public/fonts/fa-solid-400.woff2 (38 lines of unobfuscated Node.js) |
| Launcher | .vscode/tasks.json, task labeled eslint-check, byte-identical across all 79 analyzed repos |
| Trigger | VS Code runOn: folderOpen automatic task |
| Exfiltration Server | 193.32.204.199 |
| Phishing Domain | my-github[.]com (also resolves to 193.32.204.199) |
| Related Prior Wave | 772 repositories, 2,577 secrets, 373 GitHub users/organizations (Aug 31 – Sep 30, 2026) |
| Discovered By | OpenSourceMalware, following a lead from Jamf Threat Labs |
How the Fake Font Attack Works
A launcher disguised as routine linting
Each compromised repository carries a .vscode/tasks.json file defining a task labeled eslint-check — a name chosen to look like harmless project tooling. The task is configured with runOn: folderOpen, a VS Code automation feature that executes the task the moment a developer opens the project folder, and its presentation settings suppress the terminal output so the activity stays invisible. Researchers found the launcher file byte-identical across all 79 repositories they could analyze, indicating a single, mechanically repeated deployment rather than bespoke intrusions.
Execution is not automatic for every victim. VS Code requires the workspace to be marked "trusted" and automatic-task permissions to be granted before folderOpen tasks run — meaning cloning or simply browsing an affected repository does not by itself prove compromise.
The payload hiding behind a font extension
The actual malware sits at public/fonts/fa-solid-400.woff2, a path and filename designed to look like a routine Font Awesome web-font asset. Opened in a text editor, the file is not a font at all — it contains 38 lines of unobfuscated Node.js that the eslint-check task invokes directly with node. A quick way to spot the fake is that a genuine WOFF2 font reports as binary "Web Open Font Format," while the malicious file reports as plain ASCII/UTF-8 text.
What the stealer collects
Once it runs, the script harvests the victim's username and hostname, selected environment variables, and credential files associated with AWS, npm, PyPI, Git, Kubernetes, Claude, and Gemini. It also reads RSA and Ed25519 SSH private keys in full, without truncation — giving the operators everything needed to pivot into source-control, cloud, and package-registry accounts.
A persistence mechanism that outlives workflow cleanup
Unlike GhostAction's earlier workflow-injection attacks, which could be remediated by simply deleting the malicious .yml file, this stage installs a cron job that re-checks in with the attacker's server every five minutes and executes whatever command it is sent. Because the fake-font payload and its launcher are committed directly into the repository, removing a single malicious GitHub Actions workflow does not clear the infection — the .vscode/tasks.json and fa-solid-400.woff2 files must be found and deleted separately.
A companion phishing and OAuth-hijack campaign
Alongside the stealer, GhostAction's operators registered the lookalike domain my-github[.]com, pointing it at the same 193.32.204.199 server used to exfiltrate stolen secrets from the group's malicious workflows. Victims received an email from "noreply@my-github[.]com" warning of a suspicious login from Moscow, Russia, and urging them to click through to "secure" their account. The landing page functioned as a reverse proxy against real GitHub, capturing the victim's password and two-factor code in real time, then silently injecting JavaScript that completed a GitHub OAuth device-flow authorization carrying repo, workflow, and read:org scopes — without the victim ever having to confirm the approval themselves. Those scopes are sufficient to read and modify repository contents, including Actions workflow files, which maps directly onto GhostAction's original attack pattern. Researchers also flagged a related domain, my-gitlab[.]com, registered roughly 17 days earlier under the same "my-[platform].com" naming convention, suggesting the infrastructure was built for reuse across code-hosting platforms. Independent reviewers note that some specifics — whether a real token was successfully stolen in the wild and whether GhostAction's operators definitively control the domain — remain unconfirmed.
Borrowed tradecraft, possible nation-state lineage
OpenSourceMalware found the fa-solid-400.woff2 launcher technique is not original to GhostAction: it mirrors a campaign documented separately by JFrog Security Research, in which hijacked npm and Go packages used the same .vscode/tasks.json auto-run trick with a fake font asset to deploy a Python infostealer. OpenSourceMalware tracks that underlying technique as "Fake Font" and links it to a variant of Contagious Interview, a long-running campaign attributed to North Korea-aligned actors that targets developers through fraudulent job-interview lures. Whether GhostAction's operators are the same group or simply reused public tradecraft is unresolved.
Impact Assessment
| Impact Area | Description |
|---|---|
| Credential Exposure | AWS, npm, PyPI, Git, Kubernetes, Claude, and Gemini credentials, plus unredacted SSH private keys, can be exfiltrated from any machine where the task executes |
| Supply Chain Reach | 94 repositories across 66 owners confirmed in this wave alone; the broader GhostAction campaign has touched over 30,000 repositories and roughly 1,900 accounts since September 2025 |
| Persistence | A five-minute cron beacon survives removal of the originally reported malicious workflow, giving attackers a durable foothold |
| Account Takeover | OAuth device-flow hijacking via the my-github[.]com proxy can grant attackers repo, workflow, and org-read access without further victim interaction |
| Downstream Risk | Stolen tokens and SSH keys enable further repository compromise, package-registry poisoning, and lateral movement into cloud and CI/CD environments |
Recommendations
For repository maintainers and admins
- Audit every repository for
.vscode/tasks.jsonfiles containingrunOn: folderOpentasks, especially ones labeled to resemble linting or formatting checks (e.g.,eslint-check). - Search for
public/fonts/fa-solid-400.woff2or similarly named font-path files and verify their actual file type (fileor equivalent) rather than trusting the extension. - Rotate all credentials and tokens — AWS, npm, PyPI, Git, Kubernetes, and AI provider keys (Claude, Gemini) — for any machine where a suspicious task may have executed, and regenerate SSH keypairs rather than assuming partial exposure.
- Check for unauthorized GitHub OAuth app authorizations and revoke any with repo, workflow, or read:org scopes that were not knowingly granted.
- Inspect cron/crontab entries on development machines for unfamiliar jobs polling an external server every five minutes.
For security teams
- Treat "security alert" emails referencing unfamiliar domains such as my-github[.]com as phishing by default; GitHub's legitimate security notifications never originate from lookalike domains.
- Monitor outbound traffic to 193.32.204.199 and block it at the network and DNS layer.
- Extend code-review gates to flag new
.vscode/configuration files and any committed binary-looking assets underpublic/fonts/or similar paths, since these are not typically part of application logic. - Disable automatic task execution (
runOn: folderOpen) and restrict workspace trust defaults in organization-managed VS Code configurations.
For individual developers
- Do not grant workspace trust automatically when opening unfamiliar or freshly cloned repositories.
- Review
.vscode/tasks.jsonmanually before opening a new project in VS Code, particularly repositories pulled from forks or less-established maintainers. - Enable hardware-based or app-based two-factor authentication rather than SMS, and be skeptical of any "verify your login" email link — type the destination URL manually instead of clicking through.
Key Takeaways
- GhostAction has evolved from pure GitHub Actions workflow injection into a multi-stage attack combining a disguised VS Code credential stealer and GitHub account phishing.
- The malicious payload is hidden at
public/fonts/fa-solid-400.woff2and triggered via a.vscode/tasks.jsonauto-run task labeledeslint-check— a technique borrowed from the PolinRider stealer and a JFrog-documented npm/Go supply chain campaign. - The stealer targets AWS, npm, PyPI, Git, Kubernetes, Claude, and Gemini credentials, plus full, untruncated RSA and Ed25519 SSH private keys.
- A five-minute cron beacon gives attackers persistence that survives deletion of the originally reported malicious workflow file.
- A companion phishing domain, my-github[.]com, uses a reverse proxy and OAuth device-flow abuse to hijack GitHub accounts and grant repo, workflow, and read:org access without requiring active victim confirmation.
- Researchers assess the operator's tooling reflects limited technical sophistication (flawed regex filters, short grep timeouts that silently drop results), but the campaign's reach — 94 repositories in this wave alone, tens of thousands historically — makes it a significant ongoing threat to the open-source ecosystem.