How AI is changing the SOC operating model. Listen now →

close

How AI is changing the SOC operating model. Listen now →

close

BLOG

FragMiner: A Triple Threat Hiding in npm, Kernel Exploit, Supply Chain Worm, and Cryptomining from a Single Package

Michael

Baker

TL;DR: crypto-javascript@4.2.5

is one npm package that installs three things at once: a pre-disclosure kernel exploit, a supply chain worm that spreads across six build ecosystems, and a Monero miner. All three run from memory, leaving no named file on disk. The embedded kernel exploit carries a GCC build timestamp of 2026-04-30 1, seven days before public disclosure of the DirtyFrag vulnerability 23. ELF timestamps can be forged, but if this one is accurate, the actor had working weaponized code while the kernel team was still under embargo.

Executive Summary

crypto-javascript@4.2.5 appeared on npm on May 12 2026, masquerading as a cryptography utility. Its package.json contained a preinstall hook pointing at .claude/settings, a filename chosen to hide in plain sight within Claude Code project directories, which normally contain a .claude/settings.json file. One missing extension is all that separates a JSON config from a Linux ELF binary that fires the instant npm install runs.

Panther’s npm analysis pipeline alerted on the package within hours of publication. Querying Panther’s index of the npm registry for all packages associated with that account’s email (s.js.bc.ak.sggs.ksv@gmail.com) uncovered eight more packages across two additional publisher accounts, bringing the FragMiner cluster to nine packages in total. SafeDep independently flagged related packages on 2026-05-13 4. CloudSEK published a deeper technical analysis on 2026-05-14 5.

What makes this campaign notable is what was packed into a single npm package: DirtyFrag, a linux kernel exploit compiled before public disclosure, a supply chain worm that crosses six build ecosystems using a C2-delivered targeting list, and a Monero miner. The operator had pre-staged infrastructure well ahead of the attack — a cluster of 22 Tor Guard relays was deployed on 2026-04-06, 37 days before SafeDep’s public report. One relay, 207.90.194[.]2:443, appears hardcoded in the Stage 2 binary’s fallback relay table as the only entry carrying no fingerprint and no Ed25519 identity key; every other entry carries both. The cluster operator and the malware actor may be the same party. The embedded DirtyFrag LPE binary carries a GCC build timestamp of 2026-04-30 — if accurate, working weaponized code existed while the kernel team was still under embargo.

The actor published crypto-javascript@4.3.1 on 2026-05-15, two days after SafeDep’s report. Two packages remain live on npm as of this writing.

Attack flow

The diagram below shows the full kill chain for crypto-javascript@4.2.5. The worm and mining loop start automatically from Stage 2, requiring no user interaction, or operator command. The LPE (kernel exploit) is operator-gated via a C2-delivered lpe_flag, so it fires only when the operator directed. The five related packages (auth-javascript, iceberg-javascript, ms-graph-types, microsoft-applicationinsights-common, supabase-javascript) use a different Stage 0 variant with an embedded Stage 2 fallback — see “Guidance for Defenders” for how their execution profile differs.


FragMiner kill chain diagram

Technical Analysis

DirtyFrag weaponized before public disclosure

The crypto-javascript@4.2.5 Stage 2 carries a fully compiled 813 KB kernel exploit ELF: source file lpe.c, GCC 16.1.1. The GCC build timestamp embedded in the binary reads 2026-04-30.6 The five related packages carry a distinct 924 KB DirtyFrag variant, cc452646fd25653738be3ec264b55598d681838a2ceaa2208bdae0506587a183, embedded in their separate Stage 2 — both implement the same mechanism. Hyunwoo Kim (@v4bel) submitted DirtyFrag to security@kernel.org on April 29–30 7. The vulnerability was publicly disclosed on oss-security on May 7.8 Sophos published advisory SA-20260508 on May 8.9 Patches were not merged until May 8–10 10.

ELF build timestamps can be modified after compilation, so we cannot verify the actual compilation date from binary analysis alone. If the timestamp is accurate, the actor compiled a working weaponized kernel exploit during the responsible disclosure window, before any public advisory and before any patch.

DirtyFrag (CVE-2026-43284 / CVE-2026-43500) synthesizes two already-patched techniques into a new attack path on kernels where both prior fixes are in place. It escapes to a user and network namespace, installs 54 XFRM Security Associations via NETLINK_XFRM, then races vmsplice and splice to alias pipe buffer pages to /usr/bin/su’s kernel page cache, overwriting the SUID binary without an authorized write syscall. The process doesn’t need root. When it’s done, the malware can exit cleanly and the backdoor stays. /usr/bin/su is just sitting there, corrupted, waiting for the next su invocation.

Affected kernels: CVE-2026-43284 affects ≥4.11; CVE-2026-43500 affects ≥5.3. Any unpatched Linux host that ran this package should be treated as having a root backdoor in /usr/bin/su.

A worm that crosses six build systems

From the moment Stage 2 starts, the worm reads its own binary from /proc/self/exe, queries npm for up to 250 packages the victim maintains, and walks their GitHub repositories. For each uninfected repository, it uploads the Stage 2 ELF via the GitHub Git Data API and injects build hook files for whichever of these six ecosystems the target repository uses:

Ecosystem

Injected file

Trigger

Rust

build.rs

cargo build

Cargo

Cargo.toml

build directive → build.rs

Python setuptools

_buildutils.py

pip install

Python PEP 517

pyproject.toml

build-backend hijack

CMake

CMakeLists.txt

cmake ..

npm

package.json

npm install

Propagation starts the moment Stage 2 runs, there is no trigger or delay. The C2 delivers a targeting list the binary calls Futureproof, specifying which crates and repositories to prioritize on top of the victim’s own npm footprint.

Each infected repository receives 2–7 commits authored by the attacker’s GitHub account. The PAT is embedded in the binary, not fetched from C2. Commit messages follow the pattern "update <owner>/<repo>". GitHub code search returns no hits for the payload strings, consistent with propagation targeting private maintainer repositories.

Any downstream developer or CI system building from an infected repository repeats the cycle.

A Tor relay cluster deployed before the campaign

The C2 runs over Tor and the Stage 2 uses Arti, the Rust Tor client, containing a hardcoded fallback relay table. Binary analysis of the table at rodata offset 0x216000x21900 shows each entry follows the Arti format: IP:port, 40-character fingerprint, base64 Ed25519 key. 207.90.194[.]2:443 is the only entry in the table with no fingerprint and no Ed25519 key — followed by the string unmeasured value, an Arti bandwidth sentinel. Every other entry carries both.

Tor Metrics confirms that IP as fluffypancakes002ca, part of a 22-relay cluster operated by fluffypancakes.dev. All 22 relays share first_seen: 2026-04-06 23:00:00 — simultaneous deployment, 37 days before SafeDep’s blog post 11. Every relay carries Guard and HSDir flags, spread across Canada, the Netherlands, Germany, and the US.

The hardcoded onion address todlfavo4lhvwgvuy6akeutlawypmdf6wkwpdxq74rncy26rsx7sivid[.]onion appears in the same binary at BSS offset 0x285cc8. Both the relay IP and the C2 address are embedded in the same Stage 2 binary.

During Tor bootstrap, before any anonymous circuit exists, Arti contacts a fallback relay directly over TCP. If 207.90.194[.]2:443 is contacted at this stage, the relay sees the victim’s real IP without any Tor anonymization in place.

Twenty-two Guard+HSDir relays across four countries, all deployed simultaneously five weeks before the campaign was publicly detected, with the attacker’s relay as the only entry in the fallback table carrying no identity credentials.

Attribution

The crypto-javascript packages have no confirmed attribution. The related crypto-javascri cluster was attributed to an actor called Sukob by CloudSEK 12, but the two campaigns share a toolkit, not a confirmed operator. Two separate sets of accounts published packages with the same underlying toolkit in the same week.

enge31980@outlook.com published crypto-javascri@1.2.1, @1.4.5, and @3.0.1 — packages published May 11 that CloudSEK attributed to Sukob.

The crypto-javascript packages were published across three distinct accounts:

Publisher email

Packages

s.js.bc.ak.sggs.ksv@gmail.com

crypto-javascript@4.2.5

amz.hox.vz.idb.k.e@gmail.com

crypto-javascript@4.3.1, auth-javascript@0.0.17, iceberg-javascript@0.8.2, ms-graph-types@2.43.2, supabase-javascript@2.98.2, supabase-javascript@2.98.3

mi.k.hvib.ramw.el.lvf.8.6.7.2@gmail.com

microsoft-applicationinsights-common@3.4.2

The capability overlap between the two sets of packages is exact: Arti Tor client, XMRig, .claude/settings payload filename, preinstall hook delivery, /usr/bin/su page-cache targeting, supply chain worm, Rust ELF. Six independent characteristics matching across packages from distinct publisher accounts pointing at two different onion C2 addresses. The most likely explanation is a shared toolkit — a single tooling developer, possibly Sukob itself, supplying the Arti+XMRig dropper framework to at least two operators. The operator behind the crypto-javascript packages remains unidentified.

All three crypto-javascript publisher accounts use the same dot-fragment Gmail construction — letter fragments separated by dots — a pattern documented in the Famous Chollima April 2026 npm campaign (see Panther blogs 1, 2, 3). We don’t think it’s sufficient to attribute this campaign to a DPRK-linked actor. The pattern is easy to copy, no binary-level fingerprint matches any named actor. If the same construction appears in a confirmed campaign, this data will be relevant.

The GitHub token used by the worm is embedded in the binary’s RW data trailer at file offset 0x73c3d0, past the last ELF section — the same trailer mechanism that holds the Tor/C2 credentials. The analysis sample was deliberately sanitized: that region is zeroed, so the actual token is not recoverable. Static analysis ruled out C2 delivery (no token field in the Serde schema), environment variable reads (no getenv calls for GITHUB_TOKEN/NPM_TOKEN), and victim credential file access (no path lookups for .git-credentials, .npmrc, or ~/.config/gh/). The operator’s GitHub account identity is not recoverable from the sanitized binary.

Guidance for Defenders

If your team runs npm install on Linux, including in CI/CD pipelines, treat any system that installed crypto-javascript (or associated packages) in any version as fully compromised.

  • Check /usr/bin/su immediately. If the LPE ran, the su binary was overwritten in the kernel page cache. DirtyFrag does not invoke an authorized write syscall, so inode metadata including mtime may appear unchanged. Compare the SHA-256 of /usr/bin/su against your distribution’s package database directly. Any Linux host, developer workstation or CI runner, that ran this package on a kernel ≥4.11 may have a root backdoor that persists after the malware process exits.

  • Look for Arti keystore artifacts. $HOME/.local/state/arti/keys/tor+fp-sk/ on a non-Tor user’s system is a strong indicator of Stage 2 having run and beaconed.

  • Audit recently installed npm packages in CI. If you have npm install logs from 2026-04-06 onwards on Linux builders, check for crypto-javascript (versions 4.2.5 and 4.3.1), supabase-javascript (versions 2.98.2 and 2.98.3), auth-javascript@0.0.17, ms-graph-client@3.0.7, ms-graph-types, and microsoft-applicationinsights-common in any version from 2026-04 onwards. crypto-javascript@4.3.1 was published on 2026-05-15, two days after SafeDep’s detection, and is confirmed malicious (binary analysis pending). ms-graph-client@3.0.7 carries no install scripts; current assessment is target fingerprinting before dropper deployment (analysis pending). ms-graph-types and microsoft-applicationinsights-common are still live and still accumulating installs.

  • Check your GitHub repositories for unexpected commits. A commit message matching "update <owner>/<repo>" that adds a binary .claude/settings file or a _buildutils.py, modified build.rs, or pyproject.toml with build-backend = "_buildutils" is the worm’s signature. The attacker’s GitHub account authored each commit, so it will not look like your own account.

  • Block the onion and relay. Add todlfavo4lhvwgvuy6akeutlawypmdf6wkwpdxq74rncy26rsx7sivid[.]onion and 207.90.194[.]2 to your blocklists. If Tor exit traffic is visible in your environment, filter for connections to these addresses.

  • Do not clear the five support packages as benign. If your team installed auth-javascript@0.0.17, iceberg-javascript@0.8.2, ms-graph-types@2.43.2, microsoft-applicationinsights-common@3.4.2, or supabase-javascript@2.98.2/2.98.3, the full Stage 2 payload ran — not just Stage 0. These packages carried a Stage 0 variant with an embedded fallback: when the npm download of the Stage 2 payload failed (the npmj2rg package that Stage 0 tried to fetch returned 404), Stage 0 decompressed and executed Stage 2 from its own body, writing it to /dev/shm/.{name}. Stage 2 is a 7.6 MB Rust binary with Arti Tor client, DirtyFrag LPE, systemd persistence, and a Stage 3 downloader — but no mining code of its own. XMRig would have been Stage 3, delivered separately via Tor C2 or npm. Whether the operator ever served that Stage 3 payload is unknown. Check /dev/shm for any hidden files (names starting with .), check for unexpected services in /usr/lib/systemd/system/, and apply the same /usr/bin/su and Arti keystore checks described above.

Detection

At install time: Alert on package.json preinstall, install, or postinstall hooks pointing at .claude/ or any executable in a hidden dotfile directory.

In syscall telemetry (auditd, eBPF, Falco): memfd_create with name uPX or upx from a process whose parent is npm or node is the loader chain firing. unshare(CLONE_NEWUSER|CLONE_NEWNET) followed by NETLINK_XFRM socket creation and 54+ XFRM_MSG_NEWSA sends within a few seconds is DirtyFrag.

In host forensics: SHA-256 of /usr/bin/su does not match your distribution’s package database (DirtyFrag corrupts the page cache without an authorized write syscall, so inode mtime is not a reliable indicator). $HOME/.local/state/arti/keys/tor+fp-sk/ on a non-Tor user. /dev/shm/.<name> — Stage 2 for the five 19d8f3e7 packages is written here before execution (present unless cleared by the operator). Unexpected service files in /usr/lib/systemd/system/ installed around the time of package install — Stage 2 installs a system service (requiring root via DirtyFrag).

In GitHub: Commits adding a binary .claude/settings file alongside _buildutils.py, a modified build.rs containing fn main() { let _ = std::process::Command::new(".claude/settings").status(); }, or a pyproject.toml with build-backend = "_buildutils". Commits attributed to an account with no prior contribution history to that repository.

Ready for more threat research? View our team's library of work here.

Indicators of Compromise

npm packages

Package

Version(s)

Notes

crypto-javascript

4.2.5

Primary dropper, CRITICAL; full three-stage loader, DirtyFrag LPE, worm, XMRig

crypto-javascript

4.3.1

Re-arm published 2026-05-15, two days post-SafeDep detection, confirmed malicious, binary analysis pending

supabase-javascript

2.98.2

Small install-script stub

supabase-javascript

2.98.3

Full payload 4.5 MB

auth-javascript

0.0.17

Confirmed malicious

ms-graph-types

2.43.2

CRITICAL; still live on npm

microsoft-applicationinsights-common

3.4.2

CRITICAL; preinstall ELF hook; bundles legitimate Application Insights SDK; still live on npm

ms-graph-client

3.0.7

Recon: no install scripts; target fingerprinting before dropper deployment; analysis pending

Hashes

SHA-256

Role

996060ec07934561f5fc4efffea9eba7557ab5a478c00cdbe4ee710c35bae903

Stage 0 install-hook ELF

c8a494ba1e6a9e7e39d5beaa88137a0c11786e6842f6ed8a201c52d6b25dbeec

Stage 1 memfd loader (3,339 bytes)

2ffcd47b90ba0d6386d9f7dacc2861d8bcff36b7bc102a289e1107f5968921a7

Stage 2 recovered Rust ELF

19d8f3e77092270cd2cf0ef1b9ef5b3ed684e235667e0de2f84636ef7c81f724

Stage 0 variant, 1/64 VT detections

b83c5363707267395355d2842c997eceb2bad11ba25744bda1e584a9dfae1685

Stage 0 variant, 0/65 VT detections

9679fd49953b2725476461e732b42355a874666e6af7ce64c0ec410da6135222

Stage 0 variant, 1/65 VT detections

a20233d745945a50534c17328c98c77d9227afe54147b5a6806cdaa3f2f2059c

Stage 2 ELF — 19d8f3e7 chain; 7.6 MB; extracted via Unicorn emulation

cc452646fd25653738be3ec264b55598d681838a2ceaa2208bdae0506587a183

DirtyFrag LPE embedded in 19d8f3e7 Stage 2; 924 KB

Network

Value

Type

Notes

todlfavo4lhvwgvuy6akeutlawypmdf6wkwpdxq74rncy26rsx7sivid[.]onion

Tor onion

Primary C2

207.90.194[.]2:443

IP:port

Attacker relay fluffypancakes002ca; fingerprint intentionally stripped

fluffypancakes[.]dev

Domain

22-relay sybil cluster operator contact

185.227.70[.]134:443

IP:port

Tor guard relay; fingerprint 1F348BF999D4F7BE263270F5A24F69FCCEC1399C; confirmed in Stage 2 (a20233d7)

185.220.101[.]203:443

IP:port

Tor guard relay; fingerprint B7E9849D446FC57D4BDED937B8E17F3AACE1FA06; confirmed in Stage 2 (a20233d7)

217.196.147[.]77:80

IP:port

Tor guard relay; confirmed in Stage 2 (a20233d7)

Host artifacts

Artifact

Notes

.claude/settings

Hidden ELF payload in npm package; worm propagation filename in victim repos

/usr/bin/su

SUID binary overwritten in page cache post-LPE; root backdoor

$HOME/.local/state/arti/keys/tor+fp-sk/

Arti keystore written on first beacon; persistent indicator

memfd name: uPX

Stage 0 anonymous backing object

memfd name: upx

Stage 1 backing object

DIRTYFRAG_VERBOSE

LPE exploit environment variable, identifies exploit family

/dev/shm/.<name>

Stage 2 staging path (19d8f3e7 chain); written by Track 2 fallback before execution; hidden file

/usr/lib/systemd/system/<name>.service

Systemd persistence service; Stage 2 installs this after DirtyFrag root; ExecStart/Restart configured

GitHub worm markers

String

File

Ecosystem

Command::new(".claude/settings")

build.rs

Rust

subprocess.check_call([".claude/settings"])

_buildutils.py

Python

build-backend = "_buildutils"

pyproject.toml

Python PEP 517

execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/.claude/settings")

CMakeLists.txt

CMake

"preinstall": ".claude/settings"

package.json

npm

update {repo_full_name}

Git commit message

All ecosystems

  1. GCC build date extracted from the embedded LPE ELF; value 2026-04-30. The build date field is written by GCC at compile time and is not independently verifiable from the binary alone.↩︎

  2. Hyunwoo Kim (@v4bel) described the submission date in his oss-security disclosure post of 2026-05-07, placing the kernel security team submission on April 29–30.↩︎

  3. oss-security mailing list, 2026-05-07; public disclosure of DirtyFrag (CVE-2026-43284 / CVE-2026-43500).↩︎

  4. SafeDep, “Malicious npm Packages Using Claude Code Hooks,” 2026-05-13. https://safedep.io/malicious-npm-packages-claude-code-hooks/[↩︎](about:blank#fnref4)

  5. CloudSEK, “Inside a Tor-Backed Supply Chain Worm,” 2026-05-14. https://www.cloudsek.com/blog/inside-a-tor-backed-supply-chain-worm#stage-3-lpe-payload; documents crypto-javascri npm package with Arti+XMRig payload, .claude/settings filename, preinstall hook, /usr/bin/su targeting, and supply chain worm; attributed to Sukob/TeamPCP (ex-HellCat affiliate).↩︎

  6. GCC build date extracted from the embedded LPE ELF; value 2026-04-30. The build date field is written by GCC at compile time and is not independently verifiable from the binary alone.↩︎

  7. Hyunwoo Kim (@v4bel) described the submission date in his oss-security disclosure post of 2026-05-07, placing the kernel security team submission on April 29–30.↩︎

  8. oss-security mailing list, 2026-05-07; public disclosure of DirtyFrag (CVE-2026-43284 / CVE-2026-43500).↩︎

  9. Sophos advisory SA-20260508, published 2026-05-08.↩︎

  10. Linux kernel git log: CVE-2026-43284 (xfrm-ESP) fix merged 2026-05-08; CVE-2026-43500 (RxRPC) fix merged 2026-05-10.↩︎

  11. SafeDep, “Malicious npm Packages Using Claude Code Hooks,” 2026-05-13. https://safedep.io/malicious-npm-packages-claude-code-hooks/[↩︎](about:blank#fnref11)

  12. CloudSEK, “Inside a Tor-Backed Supply Chain Worm,” 2026-05-14. https://www.cloudsek.com/blog/inside-a-tor-backed-supply-chain-worm#stage-3-lpe-payload; documents crypto-javascri npm package with Arti+XMRig payload, .claude/settings filename, preinstall hook, /usr/bin/su targeting, and supply chain worm; attributed to Sukob/TeamPCP (ex-HellCat affiliate).↩︎

Share:

Bolt-on AI closes alerts. Panther closes the loop.

See how Panther compounds intelligence across the SOC.

Bolt-on AI closes alerts. Panther closes the loop.

See how Panther compounds intelligence across the SOC.

Bolt-on AI closes alerts. Panther closes the loop.

See how Panther compounds intelligence across the SOC.

Bolt-on AI closes alerts. Panther closes the loop.

See how Panther compounds intelligence across the SOC.

Get product updates, webinars, and news

By submitting this form, you acknowledge and agree that Panther will process your personal information in accordance with the Privacy Policy.

Get product updates, webinars, and news

By submitting this form, you acknowledge and agree that Panther will process your personal information in accordance with the Privacy Policy.

Get product updates, webinars, and news

By submitting this form, you acknowledge and agree that Panther will process your personal information in accordance with the Privacy Policy.