@emcd-vue/authnpm
Malicious code in @emcd-vue/auth (npm) Remove it immediately and rotate any exposed credentials.
What this malware does
Part of a coordinated multi-package supply-chain attack impersonating EMCD (emcd.io), a legitimate Russian cryptocurrency exchange and mining pool. The attacker registered the @emcd-vue npm scope to pose as an internal Vue.js front-end tooling package from "EMCD Platform Engineering." The package contains no functional library code — the entire package is a delivery vehicle for a multi-stage dropper embedded in a 137.5 KB single-line obfuscated postinstall hook (JScrambler/WaCk-style; 811-element encoded string array).
Trigger: scripts.postinstall → scripts/postinstall.js
Execution flow:
- Checks
EMCD_VUE_NO_TELEMETRYenv var as a kill-switch (README misleadingly documents a different, non-functional kill-switch name) - Computes a per-host/project dedup key to execute only once
- Detects platform (
linux-x64,darwin-arm64,win) - Downloads platform-specific second-stage:
GET https://oob.moika.tech/payload/{platform}withX-Secret: l95HdDaz3kQx1Zsg3WxH6HvKANf51RY1 - Writes payload to
~/.emcd-vue_init.js(dot-prefixed hidden file) - Spawns payload as a detached, unref'd process — persists after npm exits
- Beacons installation metadata to
https://oob.moika.tech/report
@emcd-vue/[email protected] is a hollow shell package whose only functional content is a malicious postinstall script. package.json advertises this as an 'Internal @wildberries/service-router package' (a dependency-confusion lure targeting builds that expect an internal @wildberries/* mirror), but dist/index.js is a one-line re-export module.exports = require('../src/index.js') pointing at a path that does not exist in the tarball — the package provides no library functionality. scripts/postinstall.js is heavily obfuscated using an obfuscator.io-style shuffled string array with RC4 + base64 decoders and hex-encoded property accesses; critical strings (host, URL path, secret header) are assembled only at runtime via atob(...)+atob(...) concatenation to evade static inspection. On npm install the script issues an HTTPS GET with a custom X-Secret header to the runtime-assembled URL, writes the response buffer to a randomly-named.js file under os.tmpdir(), and spawns it with process.execPath (Node) detached, stdio:'ignore', windowsHide:true, then .unref()s the child so it survives the installer. Host-identifying data is exfiltrated as part of the fetch (hostname-keyed string selection via os.hostname(), CWD walk-up via process.cwd(), Node version check), and the spawned child receives the installer's full process.env plus additional atob-decoded secret values, handing any environment-resident credentials to the attacker-controlled payload.
Malicious versions
Indicators of compromise (SHA-256)
Frequently asked questions
Campaign
References
Credits
- Amazon Inspector · finder
- SafeDep · finder
Scan your dependencies
O3 Security blocks malicious packages like this at install time and in CI.
Supply-chain protection