Older Malware Still Public on GitHub
Discord token stealers and redistributed errorHandler loaders, with published tools distinguished from victims.
Cristian Chiriac
- Published:
- 2 November 2026
- Version:
- 1.0
- Last observed:
- 30 October 2026
- Dataset frozen:
- 1 November 2026
- Collection cut-off:
- 31 October 2026, 17:59 UTC
- Tracked items rechecked:
- 1 November 2026, 18:23 UTC
- Time zone
- All dates UTC.
Contents
Two known malware families remain in public code: Discord token stealers and copied errorHandler loaders.
The research in 30 seconds
- What I found
- Two known malware families remain in public code: Discord token stealers and copied errorHandler loaders.
- What this adds
- The contribution is the pinned-commit count and the separation of published tools from affected project copies.
- Verified scope
- 202 stealer repositories, 70 copied-loader repositories and one Fernet loader on 30–31 October.
- What remains unknown
- These are not all live campaigns or confirmed victim infections; functionality was not tested.
The numbers, with their boundaries
Current count
202
Discord stealer repositories
30–31 Oct 2026 · UTC
- Counts:
- Both a hard-coded webhook with token and code reading local Discord storage; 187 owners.
Current count
70
Copied-loader repositories
30 Oct 2026 · UTC
- Counts:
- Loader copies outside the operator template set; 68 owners. Do not interpret the stealer set as 202 victims.
Not everything found in this research is a live campaign. 273 repositories carry older, publicly
documented malware. Most are Discord token stealers or copies of the errorHandler loader from the fake
coding tests; one is a Python loader with an encrypted stage.
- 202 repositories (187 accounts) hold Discord token stealers. Each contains a hard-coded Discord webhook address with its token and code that reads Discord's local storage. Most are written in Python.
- 70 repositories (68 accounts) hold an
errorHandler-style loader in a controller or bootstrap file. It is the same loader family the Contagious Interview fake job tests use. It sits in copies of those test projects that are not part of the operators' own template set. - Both families are public. What this page adds is the count at a pinned commit, and the reasons these sets are kept apart.
- On 30 October I removed three research datasets that had matched these rules: one of model outputs and two of collected malware samples. They are kept for study and are not infections.
- On 31 October I added four stealers found by a wider read of lure and tool repositories: a game-cheat DLL source, two copies of one PowerShell grabber and a single-file injector. Later that day my daily searches added 39 more stealers, and a review of the broad-rule matches added one Python loader (see What is not counted).
Nothing was executed. Owners of the loader copies are treated as victims and are not named. Authors of the stealer repositories are not named either.
Where this stands (1 November 2026)
#The proven set was closed on 1 November 2026 with what had been found up to 31 October 2026, 17:59 UTC; repositories found after that are tracked separately and are not in these figures. The full proof pass at pinned commits ran on 30–31 October. On 1 November 2026, 18:23 UTC a read-only GitHub API recheck covered the 162 repositories, 73 accounts and 12 issues that are tracked one by one (operator repositories, Shai-Hulud accounts, phishing issues), not the whole set.
- Frozen: 273 repositories under 256 accounts: 202 Discord token stealers, 70 errorHandler copies and 1 Python loader.
- Nature: published tools and copied loaders, not a campaign; the owners are not treated as victims or as operators.
Key findings
#Discord token stealers
#202 repositories proven on 30 and 31 October 2026, by the extension of the matched file; 9 files without an extension and 6 other types not shown.
Table view
| Item | Value | Note |
|---|---|---|
| Python (.py) | 148 | |
| Java (.java) | 12 | |
| PowerShell (.ps1) | 7 | |
| Batch (.bat) | 6 | |
| JavaScript (.js) | 5 | |
| C# (.cs) | 4 |
| File name | Repositories |
|---|---|
main.py |
20 |
token_grabber.py, main.ps1 |
4 each |
token.py, nuker.py, Main.java |
3 each |
stealer.py, setup.py, Setup.bat and others |
2 each or fewer |
- 148 of the 202 files are Python. The rest are Java, PowerShell, batch, JavaScript, C#,
.pyw, C++, Rust, one.etsfile, one executable and files without an extension. - Many file names call them stealers, grabbers or nukers. That suggests malware published as tools, not infections of someone else's project, although I did not check each repository's history. They are counted, but not as compromised accounts.
- 59 of the first 163 have stars, so people do find and copy them.
Copied errorHandler loaders
#| File name | Repositories |
|---|---|
userController.js |
25 |
bootstrap.js |
11 |
productController.js, product.js |
9 each |
errorHandler.js |
6 |
runtimeConfig.js |
5 |
These are back-end files of the Node.js projects used as fake coding tests. The loader evaluates a response from a remote address. Contagious Interview describes the family and the operators' own template repositories. The 70 here are separate copies, none of them forks. Where each copy came from was not traced.
What is not counted
#A broader first pass also matched these rules:
| Rule | Repositories |
|---|---|
| Python remote execution | 92 |
| PowerShell dropper | 71 |
| BeaverTail-like | 11 |
| Python Fernet-encrypted execution | 6 |
The same patterns occur in tests, scanners and legitimate installers. On 31 October I reviewed all 180 with
stricter rules fixed before reading. One counts: a Python loader that decrypts a Fernet-encrypted stage.
Decrypted statically with the key in the file, the stage downloads and runs code from easylogs[.]fun. It
is in the total. The other 179 are tests, scanners, research samples and legitimate installers, and stay out.
Evidence register
#Expand technical detail · complete record
Repository id, owner id, commit, path, git object id and matched rule for 202 stealer, 70 loader and 1 Fernet loader repositories.
Source: GitHub GraphQL, read from an isolated virtual machine · Collected 30 October 2026
Data notes and reconciliation
#Expand technical detail · complete record
| Measure | Figures | Why they differ |
|---|---|---|
| Discord token stealers | 159 → 163 → 202 | 30 Oct proof pass → +4 from a wider read of lure and tool repositories → +39 from re-run searches (31 Oct) |
| errorHandler copies | 70 | Unchanged since 30 Oct |
| Python Fernet loader | 0 → 1 | Added 31 Oct after static decryption of its stage |
| Family total / owners | 229 / 216 → 233 / 219 → 273 / 256 | Sum of the rows above |
Defensive checks
#- Never run a "grabber", "nuker" or "token checker" from GitHub. These tools steal from whoever runs them.
- In Node.js back ends, look for
Function.constructor,new Function(oreval(applied to an HTTP response, in controllers, bootstrap files and error handlers. - If you received a coding test as a repository, read Contagious Interview before running it.
Limitations
#- The stealer rule is a code pattern. It does not tell an educational repository from a working one, so some of the 202 may never have worked.
- The loader copies were not traced back to the test they came from.
- The 180 broad-rule repositories were reviewed on 31 October from the matched files; only one was counted.
Investigation context
#This article is part of the GitHub threat investigation. Counts are a snapshot, not evidence that the code ran on a victim's machine. The shared methodology and proof rules explain inclusion, exclusions and the independent re-check.
Claims, evidence and limits
| Claim | Assessment | Evidence | Limit |
|---|---|---|---|
| 202 Discord token stealers in public repositories | Confidence: Confirmed malicious | E-OF-PROOF | Not stated in the finding |
| 70 copies of the errorHandler loader outside the operators' templates | Confidence: Confirmed malicious | E-OF-PROOF | Not stated in the finding |
Terms used on this page
- pinned commit
- A specific commit, identified by its hash, at which a repository was read. Every counted repository was proven at the default-branch commit recorded in the proof pass, so a later change to the repository does not change what was proven.
- proof pass
- The 30–31 October 2026 re-read of every candidate at a pinned commit under fixed inclusion rules, followed by an independent re-read of a random sample of 555 repositories through a different API.
All terms: glossary.
Corrections & discussion
Found an error, or have evidence that supports or contradicts a finding? Send a correction. Name the section and what you observed.