Never Deleted, Only Re-Pointed: Inside the 17,600-Repo FakeGit Fleet That Re-Arms Overnight

Around 06:30 UTC on October 4, a script started editing READMEs across FakeGit, the network of fake GitHub repos that delivers the SmartLoader malware loader. Over the next thirty-four hours, more than thirteen thousand GitHub repositories were pushed in coordinated bursts, at up to 2,999 an hour. In the commits we sampled, 97% touched only the README, and 88% pointed its “Download” button at a ZIP that installs SmartLoader. Nobody had to create a single new repo. The fleet was already there. It just got re-aimed.
We call this RePointing: keep a trusted, long-lived repo, and swap only where its download button points.
17,610 FakeGit repos on GitHub are serving SmartLoader right now, and thousands of them were publicly reported months ago. We verified a SmartLoader ZIP behind every one. That is nearly double the largest list published before.
Removal is list-driven, and the lists cover a fraction of the fleet. Orchid’s 9,330-repo list from June is 99.3% gone. Island’s 7,600-repo list from July is 85% still up, 77 days on. Only 49 of Orchid’s repos are in today’s fleet, so the takedown barely touched what runs now.
One coordinated push re-armed nearly 14,000 repos in 34 hours. On October 4–5, 79% of the fleet was re-pushed in waves of up to 2,999 repos an hour. No new repos: in 97% of the edits we sampled, only the README changed. We call it RePointing. A fourth wave followed while we were writing, and another on October 6.
Blocklists barely reach the people who click. 71% of the fleet was missing from URLhaus before our report, and a domain-level DNS blocklist can’t block one file on GitHub without blocking GitHub. Of the unlisted ZIPs we sampled, security engines on VirusTotal had seen almost none. Of the ZIPs URLhaus had listed, 99.96% still downloaded. Delete one file and the operator can point the lure at a spare copy: a fork, an older ZIP, a release asset or an issue attachment.
Hundreds of real developers’ accounts are carrying it. Most of the 15,225 accounts are throwaways, but about 700 appear to be real developers’ accounts; 219 have history that other people created and that can’t be backdated. The lure commits were injected into them centrally, and the operator was still pushing to them on October 6. They pushed the kit into 270 repos they don’t own, including course and team projects.
Also inside: the operator’s C2 changelog, written to a public blockchain 21 times and the kit hidden in 167 AI skill folders.
|
Live lure repos, every ZIP verified |
17,610 |
|---|---|
|
Repos involved, counting download hosts and forked copies |
18,864 |
|
Re-pushed on Oct 4–5 |
79% |
|
Absent from our URLhaus snapshot before our report |
71% |
|
Listed ZIPs still downloadable |
99.96% |
|
Accounts behind the fleet |
15,225 |
|
Accounts that look like throwaways |
14,219 (93%) |
|
Real developers’ accounts taken over |
219 proven, ~700 estimated from hand-checked samples |
|
Bystander repos infected through them |
269+ |
GitHub malware campaigns usually scale by making more: Apiiro’s repo-confusion research counted over 100,000 automated malicious clones, and Check Point’s Stargazers Ghost Network ran 3,000+ fake accounts. This fleet barely makes new repos. It keeps the old ones and moves the download link, a mechanism a GitHub Community thread spotted in January and Orchid documented in June as recurring README-only re-pushes. Earlier reports found the lures, from SmartLoader’s first fake repos in early 2025 to Island’s 7,600-repo list in July (all under Prior work). What we add, beyond measuring the whole fleet, is the connections between things they saw separately:
Disclosure → operator. Orchid published on June 18. The operator’s last mass build day was June 17, and the next came 64 days later, against a usual gap of three.
Disclosure → takedown. Island repos that were also on Orchid’s list are 71% gone, against 14% for the rest. Being on a list correlates strongly with removal, and what’s never listed stays up.
Takeover → teammates. About 700 apparently real developers’ accounts carry the kit, 219 with third-party-verified history, and the lure commits were injected centrally on one schedule. Through them it reached 270 repos they don’t own, including course and team projects.
URL form → blocklist gap. The same bytes sit behind two URL forms; one is 51% covered by URLhaus, the other 2%. Security engines on VirusTotal had seen only 6 of 38 sampled unlisted github.com/…/raw/ ZIPs.
Inventory → waves. Push order follows the order in which lures were first armed (rank correlation 0.96), one lure per account: one sorted inventory, not separate campaigns.
Kit → detection. The July kit generation cut antivirus detections from 26–33 engines to 2–9. The newer kit is detected by far fewer engines, while nothing changed in how it hides on GitHub.

The fleet: every verified repository, clustered by payload hash and colored by the wave in which it was last pushed
Each dot is one repository, grouped around the obfuscated Lua payload it ships (120 distinct payloads) and colored by the wave in which the operator last pushed it. Every payload cluster mixes every wave: these are fleet-wide waves, not separate campaigns.

FakeGit and SmartLoader timeline, February 2025 to October 2026
What the operator did (top) against what was publicly reported (bottom).

The FakeGit attack flow, from a copied project to a stolen browser session
From lure to loot. The repo copies a real project, the README sends every click to a ZIP, and the ZIP runs SmartLoader, which finds its C2 on a blockchain and installs the StealC infostealer.
A lure takes a real project’s name, rewrites the README into a friendly install guide, and adds a download badge pointing at a ZIP buried in the repo’s own tree. A typical one, from a throwaway account (owner redacted, links removed):

A lure README: a friendly install guide whose Download badge and “Releases page” link both point at a ZIP inside the repo
Note step 3 of the install: “Windows may show a security screen. If it appears, click More info, then click Run anyway.” The guide tells the victim to click through a Windows SmartScreen warning.
The ZIPs carry fake version names like Software-v1.8-beta.2.zip and live where nobody looks: src/, assets/, docs/ and, in about 375 repos, the folders reviewers are trained to skip entirely: node_modules/, .github/, __pycache__/, dist/ and vendor/. Many more hide behind a dictionary. 5,474 lures put the ZIP in a top-level folder named with an obscure English word (ophthalmoscopic/, Arverni/). 99.6% of those words appear letter for letter, capitals included, in the 1934 Webster’s word list that ships with macOS and BSD as /usr/share/dict/words, and almost every one is used only once. The version numbers are just as mechanical: 83% of ZIPs carry one, always between 1.0 and 3.9, evenly spread, never 4.x and never a patch number.
Open one and you won’t find a project. You’ll find three or four files, with names that change from repo to repo but the same roles every time:
|
File |
Looks like |
Actually is |
|---|---|---|
|
Launcher.cmd / App.bat |
a setup script |
one line: start the runtime, hand it the “text file” |
|
luajit.exe / luau.exe / gcc.exe |
a tool binary |
a LuaJIT interpreter, renamed |
|
lua51.dll |
a dependency |
the interpreter’s library, often the same file from repo to repo |
|
userdata.txt / ico64.txt / tcp.log |
an icon, a log, a licence |
a ~300 KB obfuscated Lua program squeezed onto one line |
Detection is uneven: of the 120 distinct payload scripts we hashed, 106 are flagged on VirusTotal, and some of the newest currently score 2 to 9 of about 75 engines.
Derp, Hexastrike and Island have taken the payload apart, so in short: the launcher hides its window, profiles the machine (including a lookup to ip-api.com, which VirusTotal’s sandbox recorded for a payload shipped by 1,145 of our repos), reads its current C2 address from a Polygon smart contract (more below) and pulls the next stage from other GitHub repos. In published analyses, the chain ends with the StealC infostealer injected into a legitimate-looking process. StealC takes saved passwords, but the part that matters for developers is live sessions: a stolen cookie for GitHub, a cloud console or an SSO portal skips the login and the MFA prompt entirely.
We dated the kit across the fleet from the LuaJIT build string and PE timestamps inside each ZIP, read in memory without extracting a file:
|
First seen |
What changed |
Repos |
|---|---|---|
|
Sep 2025 |
the off-the-shelf LuaJIT interpreter, renamed |
about 1,700 |
|
Feb 2026 |
a windowless build, separate per cluster |
10,677 (61%) |
|
mid-Apr 2026 |
one shared exe and DLL for the whole generation |
3,335 |
|
late Jul 2026 |
a new obfuscator and no DLL; detected by 2 to 9 of about 75 VirusTotal engines, against 26 to 33 for the generation before |
1,811 |
New wrapper, same engine.
On October 4–5, 79% of the fleet was re-pushed, about 77% of it in three tight waves of four to five thousand repos each, peaking at 2,999 repos in one hour. We sampled 441 re-pushed repos at random where the edit could still be recovered (many were force-pushed over and no longer show in branch history). In 97% of them the edit touched only the README, and in 88% it pointed the Download link at a kit ZIP we had verified; most of the rest pointed it at a GitHub Pages site.

A re-push commit on a throwaway lure: every changed line swaps one kit ZIP link for another
One lure’s re-push (owner redacted, URLs defanged). The commit touches only the README, and every one of its 12 changed lines swaps the old ZIP link for a newer kit ZIP already sitting in the same folder.

Lure repositories by hour of last push, UTC
The waves don’t hit repos at random. The first two are the same program run twice, with near-identical minute-by-minute profiles, and each walks the lures in the order they were first armed, about 1.6 pushes a second, each from a different account: a pool of workers working through one sorted inventory.
And they push exactly one lure per account. Of the 1,101 accounts holding two or more lures, all but 2 had at most one re-pushed, usually their newest; picking repos at random would hit two or more on about 92% of them. The older lures on the same account stay up, untouched and still downloadable.
At 20:00 UTC on October 5, while we were drafting this post, a smaller fourth wave re-pushed 388 lures within the hour, mostly from one leftover cohort of accounts.
Then, on October 6, as we were finishing this post, it went again at fleet scale. By midday UTC, 8,558 of the 14,158 lures we had re-checked so far (60%) had been pushed that day, in two bursts around 05:00–07:00 and 10:00–12:00 UTC, and the second was still running when our check ended.
The tooling leaves a fingerprint: unsigned commits with the web editor’s default message (“Update README.md”) and a +0000 timezone, and fresh accounts committing from one email pattern, <first><last><four letters>@hotmail.com or outlook.com. The accounts come from a farm: 750 were registered on April 9, 2026 alone and left to age before getting a lure.
Why work this way? A repo that has existed for months, with a real project’s name and history, earns trust that a fresh fork doesn’t. Keeping the repo and swapping only the link keeps that trust, at a cost of one commit per repo. We found no sign it’s a search-ranking trick: in 120 GitHub searches for lure names, re-pushed lures ranked no better than lures left alone. It’s simply cheaper. Most of the live fleet stays up, so there’s little to rebuild; the operator only has to move the link.
Being on a blocklist is not the same as being taken down. Four findings show the gap.
Most of it was never listed. GitHub serves a raw file from two addresses, with identical bytes. In our URLhaus snapshot, their coverage is very different:

Blocklist coverage by link format
|
README link form |
Live repos |
On URLhaus |
|---|---|---|
|
raw.githubusercontent.com/<owner>/<repo>/…zip |
9,455 |
4,807 (51%) |
|
github.com/<owner>/<repo>/raw/…zip |
7,939 |
121 (2%) |
Collection pipelines look for raw.githubusercontent.com, because that’s where raw files are served from. The github.com/…/raw/ path redirects there but doesn’t match the pattern. Our own first sweep made the same mistake: fixing one regex surfaced thousands more lures in data we’d already downloaded.
It also matters who reads the list. URLhaus feeds DNS blocklists, IDS rules and antivirus, and shares with Google Safe Browsing, but a DNS block can’t stop one file on github.com without blocking GitHub. What’s left is URL- and file-level checking, and that only knows what’s listed: in a sample, all 38 URLhaus-listed lure URLs were flagged by at least one VirusTotal engine, while VirusTotal had seen only 6 of 38 unlisted github.com/…/raw/ ones.
The part that was listed stayed up. In the URLhaus-listed part of the fleet, 97% of the October re-pushes pointed the README at a ZIP URLhaus had listed in June, and 99.96% of listed ZIPs were still downloadable. A blocklist entry protects people whose tools check it. But blocklists and code hosts aren’t wired together: a listing doesn’t remove the file, and it doesn’t stop the operator from pointing the same button at the same file again.
What did get removed is what was on Orchid’s list. Orchid’s June list is 99.3% gone, almost entirely as banned accounts. Island’s July list, 77 days on, is 85% still up; Hexastrike’s April list, 24 weeks on, about half. Island repos that also appeared on Orchid’s list are 71% gone, against 14% for the rest.
The timing suggests the operator noticed. The last mass build day before Orchid published was June 17, one day earlier, and the next came 64 days later, against a usual gap of three. New accounts kept being registered through the pause and were armed in September.
Deleting the linked file isn’t enough either. The README link is only the copy that’s currently advertised. In the parts of the fleet we checked for spares:
444 forks host their own verified copy of the kit. Removing the parent leaves them up.
913 repos still hold an older, unlisted kit ZIP next to the one the README now links. Remove the listed file and the README can point at the spare in one commit.
322 release assets in 199 repos, listed on URLhaus as SmartLoader, are all still downloadable, some listed since March 2025: leftovers from the fleet’s earlier, release-based delivery.
Issue attachments carrying the kit stay downloadable even where we could find no issue that mentions them, including one on a 9,000-star open-source project that has nothing to do with the fleet.
796 download hosts are absent from our main lure list: 841 lures link a ZIP stored in a different repo, mostly the owner’s <user>.github.io, one hop from where a scanner of the lure would look. A removal list built from the lures alone misses all of them.
RePointing works because there is always something to point at.
Hunting this campaign? Match both raw.githubusercontent.com/<owner>/<repo>/…zip and github.com/<owner>/<repo>/(raw|blob)/…zip. The second form is most of what’s missing.
15,225 accounts hold 17,624 repos, so banning an account removes little more than one lure. 14,219 of them (93%) look like throwaways: 9,197 created since July 2024, and 5,022 older accounts with nothing real on them before the lure arrived. Age and inactivity are signals, not proof; some of those may be dormant accounts that were bought or taken. But some accounts are clearly not throwaways.
rushter.com also suspected account hijacking in March, and Derp named five hijacked developer profiles the same month. Island describes the fleet’s accounts as “lookalike profiles”, and most are empty or copied-project accounts. Hundreds aren’t.
We flagged 965 accounts as possible takeovers: 173 established developers with years of real contributions, and 792 more that owned a repo for at least a month, with three or more of the owner’s own commits over a week or longer, before the ZIP appeared. (Cloned lures also copy the original project’s commit history, so we count only the owner’s own commits, not the copied ones.) Then we tested them against evidence that can’t be backdated: pull requests merged by other people, write access granted to other people’s repositories, comments, forks and issues by other people, all with GitHub’s own timestamps. 219 of the 965 have that kind of third-party history before the kit appeared, usually years of it; 4 of 200 throwaway accounts do. About 200 more show years of the owner’s own work. A hand check of 180 of the 792 found two-thirds (95% interval 60–73%) to be real people’s accounts and the rest accounts the operator had aged on purpose, so the total is roughly 700, of which 219 are proven one by one. None of 120 we checked imitates an older username: they are the original accounts.
The switch shows in the commits. None of the 951 lure commits we checked is signed or made in GitHub’s web editor, although 348 of 490 owners with real history had signed their earlier work. And they were made centrally, on one schedule. Most of these ZIPs landed on February 19–23, 2026: 1,741 commits across 783 accounts, a median 23 seconds apart, with not one between midnight and 5 a.m. UTC, even on accounts where that is mid-morning. At least 80 owners went on using their accounts afterwards, merging pull requests and creating repos, with no sign they noticed; only 2 ever deleted the ZIP, and we found no public “I was hacked” posts.
And the operator still has that access. Accounts taken over in February were pushed again in October: since October 4, 40% of the lures on established developers’ accounts and 51% of those on the history-flagged ones were re-pushed (59% and 74% where the account holds a single lure). We sampled 12 established developers’ lures pushed on October 6; all 12 got the operator’s unsigned “Update README.md” commit inside that day’s wave windows, touching nothing else. Seven months on, the owners show no public sign they’ve noticed.
Holding an account this long suggests a long-lived credential, such as a token or key, rather than a single browser session. The stealer this fleet delivers is documented taking browser cookies and saved passwords, which would include a github.com login, not token files or SSH keys; a stolen session could still be used to mint a token or add a key. We can’t see from outside which credential it is or how it was first obtained, and for long-dormant accounts we can’t rule out a sale.
Then that access was used again. Between February 1 and March 19, 139 of these accounts pushed kit ZIPs into 270 repositories they don’t own (269 still infected): classmates’ projects, team capstones and course repos under university and bootcamp organizations. All 314 planted files are the kit, and 313 are still downloadable, hidden in a capstone’s node_modules/, a team’s .github/workflows/ or a Java build’s target/classes/.
The owners of those repos did nothing wrong. They gave a teammate write access, and the teammate’s account was turned against them.
Automation carries it further. One lure posing as a router add-on was picked up by the automated syncs of two community OpenWrt package feeds in late September, ZIP included. Their build scripts install only the add-on’s Lua files, so router images didn’t carry the kit, but the malware sat inside feeds that firmware builds clone. Both feeds dropped the package within a day of our public report.
We found no public sign the victims ever touched a lure before their takeover, though downloading a ZIP leaves no trace.
How do seventeen thousand ZIPs keep working when C2 servers keep getting burned? SmartLoader doesn’t hardcode one. It asks a smart contract on Polygon where to go next.
That lets the operator move the C2 without touching a repo, but every move is a public, permanent transaction. Reading the contract’s history (0x1823A9a0Ec8e0C25dD957D0841e3D41a4474bAdc, created 2025-11-15) gives the operator’s C2 changelog for this contract without sending a packet to their servers.
Derp documented this contract first, in March, with the operator’s wallet; akj.io rebuilt 15 of its updates in July. Counting every transaction the wallet has sent, against its nonce, gives 21 updates between November 2025 and September 2026, about one every two weeks, including two addresses not in any public reporting we found. (A block explorer’s list was missing 5 of the wallet’s 24 transactions, so count it yourself.) The highlights, lined up against the fleet’s activity:
|
When |
Contract update |
Around the same time in the fleet |
|---|---|---|
|
2025-11-16 |
93.123.39[.]74, the first address (a 127.0.0[.]1 test went to a separate test contract hours earlier) |
|
|
2026-02-08 |
89.169.12[.]160 |
11 days before the Feb 19–23 account takeovers |
|
2026-07-13 |
83.97.20[.]150, the last in public reporting |
|
|
2026-08-11 |
194.48.248[.]94, not in any public reporting we found |
|
|
2026-09-17 |
185.10.68[.]110, current, not in any public reporting we found |
2.5 weeks before the October waves |

New kit ZIPs per week (blue) and every C2 change on the Polygon contract (red), September 2025 to October 2026
The 21 updates came at irregular gaps, from hours to six weeks, through busy and quiet stretches alike, including the summer lull when almost no new lures appeared. The October waves didn’t coincide with one.
4,551 lures (26%) share their exact name with a real project that has at least 50 stars (16.6 million stars in total). 46% of those lures copy AI, MCP, Claude or agent tooling: mattpocock/skills (26 lures), anthropics/claude-code (12). They borrow trust through the names, not stars: almost all have few or none. Often the code comes too. In a random sample of 82 name-matched lures, 30 (37%) carry at least 90% of the real project’s files byte for byte, as they stood on the day the lure was made, a median two weeks after the original appeared; 9 more carry part of it. A copy of NVIDIA’s garak scanner keeps 525 of its files unchanged; a copy of sapientinc/PRAXIST appeared two days after the project did, with nearly 4,000 of its files. What’s added is the ZIP and a README whose links were repointed to it. The rest borrow the name, with other files or none. 1,169 lures have live listings on AI skill directories, led by awesomeskills.dev (1,052) and skills.lc (169), each with a copy-paste install command.
That command is the sharp edge. In 167 lures, the kit ZIP sits in the same folder as a SKILL.md that never mentions it, and 96 of those are listed on a directory. npx skills add clones the repo and copies that whole folder, ZIP included, into the agent’s skills directory, and nothing about the skill itself looks wrong. The lures don’t rely on this route; their READMEs link the ZIP directly. And landing on disk isn’t running: nothing is extracted or started until someone, or some agent, opens the ZIP and runs the launcher. But it puts the malware one step closer to the machine that has your keys.
The lure text reads machine-written. 87% of repo descriptions on the fleet’s new accounts run past 100 characters, against 4% of random GitHub repos; 31% open with an emoji and 38% with a command verb (“Build…”, “Automate…”), against well under 1% of random repos for either. The READMEs follow the same register: friendly, numbered, padded with system requirements. Trend Micro flagged AI-written lures for this malware in 2025, so the writing itself isn’t news. What’s new is what the text gives away about how it was made.
Nobody reads it before it ships. In a sample of 2,191 lure READMEs, 17 begin with a stray ````markdown` fence, the wrapper a chat model puts around its answer, pasted in whole; 13 keep the model’s own note to the user, such as “This README paraphrases and expands upon the provided information”; 39 tell people to run an Android, iOS or Linux project on “Windows 10 or Windows 11”. None of the 157 human-written READMEs of the hijacked real projects we used as a control has any of these. And each one is generated fresh: among 2,196 READMEs we found 2,116 distinct section layouts and only four exact duplicates. The headings shift on particular days, as if someone revised the prompt, but we found no link to public model releases.
The delivery is mechanical. In the October waves, pushes came about 1.6 a second, in the order the lures were first armed. In the February takeovers, commits landed a median 23 seconds apart, never between midnight and 5 a.m. UTC, and 2,194 of 2,385 copied the previous commit’s message word for word. The folder names that hide the ZIPs come from Webster’s 1934 dictionary file, a word list any script can read, not a model’s choice. The February takeovers were two commits each: one adding only the ZIP but titled “Update README.md”, then a README rewrite a median two hours later, in all 59 pairs we diffed, with no fix-ups, reverts or retries anywhere. As we read it, a script calls a model once per repo and publishes whatever comes back, on a human working schedule. That isn’t an AI agent running the campaign; it’s a pipeline nobody proofreads.
Every new angle we tried found more. Commit metadata, GitHub’s public event archive, the GitHub Pages hop and the other repos of accounts we’d already found together added about 3,000 lures that no keyword search had surfaced.
Comparing our search with URLhaus’s independent collection (a Lincoln–Petersen estimate) suggests we find roughly 84% of lures using the raw.githubusercontent.com form. If the other link forms are found at a similar rate, the live fleet is around 21,000 repos. That rests on assumptions that don’t fully hold, such as two independent collections with similar blind spots, so read it as a rough size, not a bound. A second estimate, against Island’s independent July list, lands at about 22,000. The hard number is what we saw: 17,610 live lure repos at our final snapshot.
Developers and AI-agent users
Never run a .cmd, .bat or .exe from a ZIP linked in a README, even from a repo with exactly the right name.
Install skills and MCP servers from the official registry or the vendor’s own repository.
Treat any infostealer infection as a GitHub compromise: revoke sessions and tokens, and move to passkeys.
Security teams
Hunt for archives containing a batch file, an executable containing the string LuaJIT, lua51.dll, and one large single-line text file.
Block both URL forms at the proxy.
Watch the Polygon contract. A new updateData transaction means a new C2 address to block, usually every couple of weeks; it’s the cheapest IOC feed this fleet offers.
Platforms and directories
Feed blocklist entries for hosted content into removal: a listed URL that’s still live is the gap this fleet lives in.
Watch for RePointing itself: a README edit that only changes a download link to a ZIP inside the same repo, across thousands of repos in the same hour, is not normal developer behavior.
Removing a lure? Check its forks, older ZIPs in the tree, release assets, attachments and any other repo its README downloads from.
Flag ZIPs committed into node_modules/, .github/ and build output folders.
Re-scan listed READMEs on a schedule: lures turn malicious after they’re listed.
This fleet lives in the gap between “listed” and “blocked”, and it also targets the coding agents that install tools on a developer’s behalf. Guardian Protect, part of Apiiro’s Guardian Agent, works on the developer’s machine. It checks the install commands a coding agent wants to run against policy (known-malicious and low-reputation packages, and dependencies pulled from somewhere other than the real registry) and blocks them before anything is fetched or executed. It also inventories the dev tools and open-source components already on the endpoint.
Get a demo of Guardian Agent.
GitHub: the full list as re-checked at 14:56 UTC on October 6, 17,601 repositories and 15,211 accounts, each triaged, with hijacked accounts flagged for recovery (revoking sessions and tokens) rather than a ban.
URLhaus: 13,786 previously unlisted, verified-live ZIP URLs submitted on October 5–6, plus a note on the github.com/…/raw/ collection gap; 15 more for the other malware families.
ThreatFox: the two newest SmartLoader C2 addresses from the contract.
Others: both OpenWrt feeds that auto-mirrored a lure (they dropped it within a day), and three AI skill directories.
SmartLoader payload clusters (SHA-256 of the obfuscated Lua payload):
|
Payload SHA-256 |
Repos |
VT |
|---|---|---|
|
8cede35b80b1deaf732c2b178d908f91b3e7a0c114d06dfae9075b8a9bf78b8f |
1,145 |
33 |
|
f9436ccb986760ca379d6cd2f00726e032a1d9c250a9bd261d40d98b914e7ef9 |
795 |
34 |
|
73f3c4ae76c086f962a06d790be6cc104a47c9d1bfcaebd12eebb3455b090660 |
511 |
8 |
C2 dead-drop: Polygon contract 0x1823A9a0Ec8e0C25dD957D0841e3D41a4474bAdc; newest entries 194.48.248[.]94 (2026-08-11) and 185.10.68[.]110 (2026-09-17). Read from the chain only, never contacted.
|
Other malware behind the same style of fake install guide |
SHA-256 |
|---|---|
|
Release.exe (nexe loader, 7 repos) |
18750cfa651271dc086f6806ac01c3c9d621e949b6127ff199a174cb774d8064 |
|
kidkadi.node (in-memory PE mapping) |
33bba47346c03968977688bddbdd245210c06fb7686b4dfc78789c70e2a95219 |
|
libcurl.dll (sideloaded by signed WinGup) |
77e46759791c9230afc29baeb6cb048a9a05196db1a48705dd94aa2e74b93e0e |
Full repository, URL and hash lists are available to defenders on request.
This fleet was found piece by piece. In order (the first entry and rushter.com describe the same playbook but don’t analyze the payload, so we can’t confirm it’s the same kit):
February 2025, r/github: new repos cloned within hours to serve an infostealer (RedLine, via Releases); a GitHub-flaired account replied that Platform Security was likely aware.
March 2025 onward, Trend Micro, ASEC and others: SmartLoader in fake GitHub repos, delivered through Releases.
January 2026, GitHub Community discussion: README links switched to ZIP files, and compromised forks.
March 2026, Derp: the LuaJIT kit, both Polygon contracts, the operator’s wallets and five hijacked developer profiles. rushter.com: the software-v*.zip search pattern, which matches this kit’s ZIP names, and the first suspicion of account hijacking. Netskope named the actor TroyDen.
April 2026, Hexastrike: 109 repos, the full infection chain to StealC.
June 2026, Orchid: 9,330 repos found through GitHub’s public event archive, and the README-only re-pushes.
July 2026, Island: 800 fake AI skills and MCP servers, and a list of 7,600 repos. akj.io: 15 C2 rotations and the dead-drop decryption key.
GitHub GraphQL search across README templates and ZIP-name patterns in adaptive push-time windows, widened with commit metadata, GH Archive events (the hunting approach Orchid published in June), GitHub Pages and cross-repo links. For every candidate we fetched the README and each linked ZIP and matched the ZIP against the kit structure in memory. Nothing was extracted or executed, including the other families. VirusTotal was used for hash lookups only; C2 infrastructure was observed passively (on-chain data, DNS and RDAP). Numbers come from a freeze at 2026-10-06 07:41 UTC. “The operator” is shorthand for whoever controls the coordinated pushes; the evidence shows shared tooling and timing, not a single named actor. Account categories (throwaway, takeover) are heuristics from public account and commit history.
We also cross-checked the published lists from Island (7,600 repos), Orchid (9,330) and Hexastrike (109). 6,237 of Island’s repos were already in ours. The few still serving the kit that we lacked, 67 from Island and 1 found with Orchid’s search pattern, are included in our counts.