On July 31 and August 1, 2022, one PyPI publisher uploaded 12 packages in roughly 24 hours — hackerfilelol, stealthpy, plutos, testpipper, pippytest, cyphers, rblxtools, and five close variants — and every one of them dropped Windows credential-stealing malware on install. Snyk's security research team caught the batch through static analysis and documented the full chain: packages that used PyInstaller to bundle two executables, ZYXMN.exe and ZYRBX.exe. ZYXMN.exe harvested saved passwords, cookies, and browsing history from Chrome and hijacked Discord tokens by injecting the Discord client itself; ZYRBX.exe reached into Edge, Chrome, Chromium, Firefox, and Opera to steal Roblox .ROBLOSECURITY session cookies along with account ID, Robux balance, and premium status. Both executables were downloaded from cdn.discordapp.com during install, and the stolen data went back out the same way, over Discord webhooks — a channel that blends into normal developer traffic on most corporate networks. None of these names were exact typosquats of famous libraries like requests or numpy; they were plausible-sounding utility names ("pip tester," Roblox tooling) designed to look like exactly what a developer searching PyPI would expect to find. This piece walks through how that attack pattern works end to end, and what a registry or an internal proxy needs to check to catch it before pip install finishes.
What makes a package name convincing instead of an obvious typo?
Classic typosquatting relies on visual similarity — reqeusts for requests, a transposed pair of characters a tired developer won't notice. The 2022 Discord/Roblox campaign Snyk documented used a different lure: names like testpipper, pippytest, and rblxtools aren't misspellings of one specific famous package, they're generic-sounding utility names that match what someone would plausibly type into a search bar — "a pip testing tool," "a Roblox tool." That's a harder pattern to catch with a fixed edit-distance check against a top-1000 package list, because there's no single legitimate package being impersonated. Effective detection has to combine name-similarity scoring with signals that don't depend on naming at all: a brand-new publisher account, zero prior release history, and a burst of near-identical uploads in a short window are all present regardless of whether the name is a typo or a lure. The 12-package upload in a single day is itself a signal — legitimate maintainers rarely publish a dozen unrelated first-time packages together.
How does a Python package end up running a Windows executable?
The chain runs through setup.py or an install-time hook that downloads or unpacks a bundled binary rather than through anything a pip install dry-run would flag as "just installing a Python library." In the campaign Snyk analyzed, the packages used PyInstaller — a legitimate tool for turning Python scripts into standalone .exe files — to ship ZYXMN.exe and ZYRBX.exe inside the package archive, then executed them as part of install. PyInstaller is the same tool thousands of honest projects use to distribute CLI tools, so its presence alone isn't a signal; what matters is a Python source package embedding a compiled Windows PE binary at all, combined with install-time code that executes it rather than merely referencing it as a dependency artifact. A source package that ships no .py logic of consequence but does ship an .exe is a strong behavioral outlier — the overwhelming majority of legitimate PyPI packages ship pure Python or well-known compiled extensions (.pyd, .so) tied to a build toolchain, not arbitrary standalone executables.
Why do stealers use Discord webhooks instead of a dedicated server?
Standing up your own command-and-control server costs money, needs DNS and TLS, and gets fingerprinted and blocklisted quickly once a security vendor notices the traffic. A Discord webhook is free, requires no infrastructure of the attacker's own, and rides over discord.com and cdn.discordapp.com — domains that appear constantly in normal corporate and developer network traffic and are rarely blocked outright. Snyk's writeup on the 2022 campaign found the stolen browser, Discord, and Roblox data was exfiltrated this way; the malicious executables themselves were also pulled from Discord's CDN during install rather than attacker-owned hosting, so the entire chain rode on infrastructure that looks legitimate. The tactic isn't unique to this campaign — commodity infostealers across the ecosystem lean on Discord and Telegram webhooks for the same reason. For defenders, this means a network-layer allowlist that treats Discord as "known-good" is the wrong control; the useful signal is a Python package's source or install script containing a hardcoded webhook URL or bot token at all, which almost no legitimate package needs.
What does the malware actually target once it runs?
The two executables in the 2022 campaign split the work: one harvested general browser and desktop credentials, the other specialized in a gaming platform's session data — and the split illustrates how targeted these payloads had become past 2022. ZYXMN.exe pulled saved passwords, cookies, web history, search history, and bookmarks from Chrome, then injected the running Discord client with a persistent malicious agent to exfiltrate Discord tokens — the same injector also skims credit card numbers in real time if a victim types one in after it loads, rather than pulling them from browser storage. ZYRBX.exe reached across Edge, Chrome, Chromium, Firefox, and Opera to go after Roblox specifically, stealing the .ROBLOSECURITY cookie along with account ID, Robux balance, and premium membership status — data with direct resale value on gray markets for in-game currency and accounts. To reduce detection, the executables were renamed to random Windows-style identifiers (patterns like WIN-siP1VyGDrfCYO2k3.exe), dropped into an unusual path (C:\$Windows.~SXK), and self-deleted after running, leaving little forensic trail on the host beyond whatever the credential theft already achieved.
What can a registry or an internal proxy actually check before install?
Because the payload lives inside the package archive, the most reliable control point is before pip install finishes — inspecting the archive's contents statically, without executing any code, and stopping the install if it looks wrong. That means checking for embedded compiled binaries in a source distribution, install-time hooks that reach out to unfamiliar hosts (including CDN domains normally considered benign), hardcoded webhook or token strings, and metadata anomalies like a first-time publisher shipping a dozen packages in one sitting. None of these checks require having seen the specific malware family before, which matters because attackers rotate package names and binary hashes constantly to dodge blocklists. Registries that only check uploads against known-malware signatures will always be one campaign behind; behavioral and metadata heuristics generalize to the next campaign that hasn't been named yet.
How Safeguard helps
Safeguard's Package Firewall runs as an install-time proxy in front of pip and npm, so every fetch — including transitive ones — is evaluated before code reaches disk, using static behavioral analysis that introspects a package's contents without executing it. That's the layer built to catch exactly this pattern: a source package bundling a compiled Windows binary, an install hook reaching out to discordapp.com or another exfiltration endpoint, or a name that mimics a plausible utility rather than a known library. Behind it, Eagle — Safeguard's malware classification model — scores every PyPI publish across seven indicator classes including install-script behavior, egress patterns like Discord/Telegram exfiltration, credential-harvesting file access, and typosquat similarity, and retroactively re-scores the historical corpus whenever its model updates, so a package that looked benign on day one gets flagged the moment a new signal is learned. Findings from either layer land in Safeguard's unified findings model with the specific rule that fired, so a security team can see whether an install was blocked, quarantined, or merely flagged for review — and tune enforcement from audit mode up to hard blocking as confidence grows.