Inside StegaBin: How a DPRK Steganography Campaign Generated Headlines
In late February 2026, a North Korean threat actor published 26 malicious npm packages across throwaway accounts over the span of two days. The packages used text steganography to hide command-and-control URLs inside Pastebin posts disguised as computer science essays. They deployed a nine-module infostealer and RAT targeting browser credentials, crypto wallets, SSH keys, and VS Code configurations. The infrastructure spanned 31 Vercel deployments with automated fallback.
The campaign generated a wave of coverage: The Hacker News, SecurityOnline, GBHackers, DevOps.com, and others all ran stories. Socket published a detailed research blog expanding the original 17 packages to 26.
As far as we can tell, the packages saw negligible real-world adoption. That's consistent with what these campaigns typically look like in practice.
Timeline
Date | Event |
|---|---|
February 11, 2026 | Pastebin dead-drop posts created |
February 25, 2026 | First malicious npm packages published (\~19:38 UTC) |
February 26, 2026 | Final batch published (\~10:35 UTC) |
\~March 2, 2026 | kmsec.uk publishes original research (17 packages); Socket expands analysis to 26 |
March 2-3, 2026 | The Hacker News, SecurityOnline, GBHackers, and others publish coverage |
March 6, 2026 | All packages flagged and removed from npm |
March 9, 2026 | All 26 advisories published in Snyk Vulnerability Database |
What StegaBin actually does
Before we get to what the data tells us, the technical work here is worth understanding. The campaign, attributed to the DPRK-aligned threat group tracked as Contagious Interview (also known as FAMOUS CHOLLIMA, DeceptiveDevelopment, and PurpleBravo), represents an evolution in how npm malware resolves its C2 infrastructure.
The packages
Between February 25 and 26, 2026, 17 packages were published across individual throwaway npm accounts. Security researcher kmsec identified the initial batch; Socket later expanded the count to 26. All packages follow the same pattern: typosquats of popular libraries with plausible-sounding names.
Package | Mimics | Published |
|---|---|---|
| dayjs | Feb 26, 10:35 UTC |
| cors | Feb 26, 10:33 UTC |
| sequelize | Feb 26, 10:16 UTC |
| express | Feb 26, 10:05 UTC |
| lodash | Feb 25, 22:31 UTC |
| fastify | Feb 25, 22:07 UTC |
| vitest | Feb 25, 22:21 UTC |
| prism | Feb 25, 22:13 UTC |
| argon2 | Feb 25, 21:51 UTC |
| bcrypt | Feb 25, 21:46 UTC |
| ethers | Feb 25, 19:38 UTC |
(Full list of 26: argonist, bcryptance, bee-quarl, bubble-core, corstoken, daytonjs, ether-lint, expressjs-lint, fastify-lint, formmiderable, hapi-lint, iosysredis, jslint-config, jsnwebapptoken, kafkajs-lint, loadash-lint, mqttoken, prism-lint, promanage, sequelization, typoriem, undicy-lint, uuindex, vitetest-lint, windowston, zoddle)
Every package contains identical malicious code at vendor/scrypt-js/version.js (SHA256: da1775d0fbe99fbc35b6f0b4a3a3cb84da3ca1b2c1bbac0842317f6f804e30a4). An install script in the package's package.json triggers node ./scripts/test/install.js, which simply imports and executes this payload.
The steganography trick
This is the part that earned the campaign its name and its headlines.
Rather than hardcoding C2 domains (which are trivially blocklisted), the malware fetches three Pastebin posts containing what looks like ordinary computer science essays. Hidden inside the text are C2 URLs encoded through character-level steganography: characters at evenly-spaced positions throughout the essay have been replaced to spell out infrastructure addresses.
The decoder:
Strips zero-width Unicode characters from the fetched text
Reads a 5-digit length marker from the beginning
Calculates evenly-spaced character positions across the text
Extracts the character at each position
Splits the result using a
|||separator, terminating at===END===
The three Pastebin dead drops were created on February 11, 2026, two weeks before the packages were published:
Pastebin URL | Author | Views |
|---|---|---|
| davidsouza23 | 353 |
| Edgar04231 | 15 |
| Edgar04231 | 19 |
The view counts tell their own story. The primary paste was hit 353 times (likely a mix of researcher scanning and actual malware executions). The fallbacks barely registered.
Platform-specific payload delivery
The decoded C2 URL points to a Vercel deployment (ext-checkdin[.]vercel[.]app), with 31 fallback domains using patterns like cleverstack-ext301, brightlaunch-app615, neuraldock-ext126. Non-curl user agents get a "Permanently suspended" decoy page.
The Vercel endpoint serves platform-specific shell payloads:
All three variants run detached (spawn(shellPath, shellArgs, { stdio: 'ignore', detached: true })), leaving no console output.
The nine-module infostealer
The final payload is a modular toolkit designed to comprehensively extract credentials and secrets from a developer's machine:
Module | Target | Technique |
|---|---|---|
bro | Browser credentials | Harvests saved passwords from Chrome, Firefox, Opera, Edge |
j | Crypto wallets | Targets 86 browser extension IDs (MetaMask, Phantom, Coinbase Wallet, etc.) |
vs | VS Code | Injects persistent |
clip | Clipboard/keylogger | Polls clipboard every 500ms, low-level keyboard hooks, exfiltrates on 10-min cycles |
git | SSH keys & Git credentials | Extracts |
z | File system | Pattern-based enumeration and exfiltration of matching files |
truffle | Secrets in code | Downloads and runs TruffleHog, a legitimate secrets scanner, against local repos |
n | Remote access | Persistent WebSocket RAT (connects to |
sched | Persistence | Redeploys and re-establishes all modules after reboot |
The TruffleHog module is a particularly interesting choice: rather than building their own secrets scanner, the attackers download and weaponize an open-source security tool to find API keys, tokens, and credentials in the victim's codebase.
Did anyone actually install these?
All 26 packages were flagged by npm and removed. Advisories for all of them are available in the Snyk Vulnerability Database.
Based on the Pastebin view counts (353 on the primary paste, 15 and 19 on the fallbacks) and the fact that these were brand-new packages with zero prior download history, real-world adoption appears to have been negligible.
That's not surprising when you look at the campaign design. These are brand-new packages with no download history, no dependents, and no reason for any real project to include them. The names are close enough to real packages to trick someone who misremembers a package name, but expressjs-lint is not going to show up in anyone's lock file by accident. These packages reach victims through a specific social engineering workflow: a fake recruiter sends a candidate a "test project" that includes the malicious package in its dependencies. The target is individual developers during job interviews, not production systems.
A recurring pattern
The Contagious Interview campaign has been running since late 2023, part of a rising trend of malicious packages in open source ecosystems. DPRK-aligned groups have published hundreds of malicious npm packages across dozens of waves. Socket tracks these closely and has published detailed research on multiple iterations. The techniques evolve (Bitbucket payloads, then direct stagers, then Google Drive, now steganographic Pastebin dead drops), but the fundamental approach is the same: publish new throwaway packages, use them in targeted social engineering, and hope the target installs them.
Each wave generates a fresh round of headlines, and each time, the real-world enterprise impact is negligible. Nobody's package-lock.json is pulling in zoddle or daytonjs. The attack vector is social engineering aimed at individual developers, and the packages are the delivery mechanism, not the infiltration point.
When malicious packages do matter
The malicious package campaigns that warrant incident response are the ones that compromise packages already in your dependency tree.
In September 2025, the Shai-Hulud worm spread through trojanized versions of ngx-bootstrap, ng2-file-upload, and @ctrl/tinycolor, packages with real download numbers and real dependents. That campaign injected malicious postinstall hooks into legitimate packages, harvesting npm, GitHub, and cloud credentials from developer machines and CI agents. By November, its successor SHA1-Hulud had impacted over 600 distinct npm packages, including popular packages from Zapier, PostHog, and Postman.

Shai-Hulud NPM Attack: Remediation with Snyk
For a deeper look at how legitimate package compromises work, see the Compromise of legitimate package lesson on Snyk Learn.
What this means for your security program
For most organizations, the practical risk from throwaway malicious package campaigns is low. Here's what helps:
1. Know what's in your dependency tree. If you can answer "do we use any of these 26 packages?" in minutes rather than days, you're in a good position. Tools like Snyk Open Source flag malicious packages as part of every scan, so once advisories are published, affected projects surface automatically.
2. Lock your dependencies. Use lock files (package-lock.json, yarn.lock) and review changes to them in pull requests. Throwaway malicious packages only enter your codebase if someone explicitly adds them. A lock file diff showing a new, unknown package is a clear signal.
3. Focus incident response on what reaches production. When a malicious package campaign makes headlines, the first question to answer is: "Are any of these in our projects?" If the answer is no, acknowledge the threat, confirm you're not affected, and move on. Save the deep investigation for cases where compromised packages are already in your dependency tree.
4. Educate developers about recruitment-based social engineering. The Contagious Interview campaign targets developers directly through fake job interviews and "assessment projects." The technical sophistication is in the malware, but the initial access is old-school social engineering. Developers should be cautious about running unfamiliar projects from recruiters, especially those that require npm install with packages they don't recognize.
For more on securing your npm dependencies, see NPM Security: Preventing Supply Chain Attacks and How to Prevent Malicious Packages on the Snyk blog.
IOCs
For detection teams, the key indicators from this campaign. Full IOC sets are also maintained by starmtp/IOCs, kraven-security/hunting-packages, and stamparm/maltrail on GitHub.
File hashes (SHA256):
Network indicators:
Host indicators:
~/Library/tokenlinux.sh(macOS)~/.config/tokenlinux.npl(Linux)%APPDATA%\parse\token.cmd(Windows)Modified
.vscode/tasks.jsonwith 186-space whitespace padding (VS Code persistence viarunOn: "folderOpen"trigger)
Process behavior:
Node.js spawning
curlorwgetNode.js DNS lookups to
pastebin.comcurl/wgetuser-agent requests to Vercel deploymentsTruffleHog binary execution from non-standard paths
WHITEPAPER
The AI Security Crisis in Your Python Environment
As development velocity skyrockets, do you actually know what your AI environment can access?