SafeDep researchers found three npm packages — mathmain, mathsbase, and math-universe — hiding an encrypted remote access trojan that stays dormant until a specific mathematical matrix passes through the solver. The decryption key isn’t stored anywhere in the code. It materializes transiently as the output of an LU decomposition on a 3×3 Pascal matrix — and then it unlocks an AES-256-GCM encrypted RAT with shell access, blockchain-based C2, and a Slack command loop. JFrog confirmed the findings independently on September 21, 2026.
How the npm Encrypted Loader Trigger Works
The malicious code hides inside lusolve(), mathjs’s linear equation solver. An extra function call was inserted that passes the LU decomposition’s lower triangular factor to isGraph() — a function that looks like a routine validation utility. Inside isGraph() sits a hardcoded AES-256-GCM encrypted blob, decryption logic, and scrypt key derivation routines.
When lusolve() receives the specific Pascal matrix [[1,1,1],[1,2,3],[1,3,6]], it produces a lower triangular factor L = [[1,0,0],[1,1,0],[1,0.5,1]]. That matrix, JSON-stringified, becomes the decryption password. The same password unlocks the encrypted payload files in all three packages. The password never exists in source code — it only exists for the fraction of a second during the mathematical computation.
This is why SafeDep tested 16,922 possible passwords before JFrog recovered the exact trigger matrix through independent analysis.
// The trigger — this specific matrix unlocks the payload
lusolve([[1,1,1],[1,2,3],[1,3,6]])
// Produces L = [[1,0,0],[1,1,0],[1,0.5,1]]
// JSON.stringify(L) becomes the AES-256-GCM decryption key
The Payload: Slack, Blockchain, Shell Commands
Once decrypted, the implant runs in three stages. Stage one handles reconnaissance: it generates X25519 key pairs, executes shell commands, and reads data from a smart contract on the Base Sepolia testnet using a bundled ethers library. Stage two polls Slack’s conversations.history API every ten seconds for operator commands, executing them via shell. Stage three provides the blockchain interface for C2 operations.
Two variants exist across the three packages — different smart contract addresses but shared Alchemy API credentials — indicating a single operator. Commands arrive through Slack and blockchain networks, not a static IP address. There is no IP to block and no persistent command log. The implant also requires a CHAT_PASSWORD environment variable to function, which points to a second cooperating package as part of a multi-stage attack design.
Why Standard Tooling Misses This Attack
This npm encrypted loader malware was engineered to defeat the defenses most development teams actually run. It uses no install scripts, so npm’s install-time filters never trigger. It stores no plaintext credentials or indicators of compromise for static scanners to match. The GitHub source repositories for all three packages were clean — the malicious code exists only in the published npm tarballs. No CVE has been assigned, so npm audit, Snyk, and Dependabot return clean results.
Furthermore, the encrypted payload is inert by default. A scanner examining the package finds an encrypted blob and a function that looks like a validation check. Without knowing the trigger matrix — and without a second package that supplies it — the attack never activates. Static analysis alone cannot catch this. The only tools with a realistic chance are those performing behavioral analysis at install time, examining what code actually does rather than matching known-bad signatures. Tools like Socket.dev represent this approach; most teams haven’t added them yet.
Where This Fits in 2026’s npm Attack Wave
The mathmain campaign is not an isolated event. The 2026 npm ecosystem has seen the ChainDrop worm hit 444 packages in August, the ViteVenom campaign use blockchain for C2 in July, and the indexed-btree loader hide payloads in runtime methods to evade install-hook detection. However, the mathmain attack introduces something new: a cryptographic trigger derived from mathematical computation. Neither component — the malicious package nor the trigger — is dangerous alone. Together, they activate a full remote access capability.
According to supply chain attack tracking data, 454,600 malicious npm packages were flagged in 2025 alone — a 75% year-over-year increase. The average supply chain breach takes 267 days to identify and costs $4.91 million. The mathmain attack’s cryptographic sophistication represents where this threat category is heading.
What Developers Must Do Now
Start with your immediate exposure: check your lockfile for mathmain, mathsbase, or math-universe. If any appear, remove them and audit the systems that ran them using the SHA-256 hashes in the SafeDep technical analysis. Then address the systemic gap these packages exposed:
- Run
npm ciin CI pipelines instead ofnpm install— it requires a committed lockfile and refuses silent upgrades - Add
--ignore-scriptsto npm installs in CI to block install-hook attacks (this attack didn’t use them, but many others do) - Add Socket.dev to your PR pipeline for behavioral analysis on every dependency change
- When evaluating unfamiliar packages, compare the published npm tarball contents to the public GitHub source — a discrepancy is a definitive red flag
- Monitor Node.js processes for unexpected outbound connections to Infura or Alchemy RPC endpoints
The larger lesson is that npm audit and CVE-based scanning were never designed to catch this category of attack. They catch known vulnerabilities in code you trust. The mathmain campaign hid malware inside a trusted-looking package, used math to hide the key, and activated only under controlled conditions. The 2026 npm threat ecosystem has evolved past what 2024-era tooling was built to detect.













