Security Research

A Popular Solana Bot on GitHub Was a Wallet Thief: Supply Chain Attack Analysis

#Supply Chain Attack#Malware#Sample Analysis#Web3 Security
Over a near-black teal-blue background, a GitHub repo crowned with inflated Stars and Forks, a hijacked npm dependency URL in package-lock.json rerouting to a rogue package, and copper-orange exfiltration arrows flowing toward a C2 server — symbolizing the Solana trading bot supply chain attack on GitHub

Background

On July 2, 2025, a victim contacted the SlowMist Security Team for help analyzing why their wallet assets had been stolen. The trigger: the day before, they had used an open-source project hosted on GitHub — zldp2002/solana-pumpfun-bot — and shortly after, their crypto was gone.

We got to work immediately.

Sample Identification

Visiting the GitHub repo, its Star and Fork counts looked respectable enough. But every directory showed commits concentrated within a three-week window — a clear red flag. A legitimate project would show a more natural update cadence.

GitHub repo screenshot

The project is Node.js-based. Our first step was to examine its dependencies. One immediately stood out: crypto-layout-utils.

Suspicious dependency in package.json

Digging deeper, we found this package had already been removed from the npm registry. The version specified in package.json didn’t appear in npm’s version history at all. We flagged it as suspicious — and by then it was no longer downloadable from the official npm source.

This raised the obvious question: how did the victim even get this malicious dependency?

npm version not found

Dependency Hijacking

Digging further into the project, we found the smoking gun in package-lock.json: the attacker had replaced crypto-layout-utils’s download URL with a GitHub Releases link.

Replaced download URL in package-lock.json

The substituted URL:

https://github.com/sjaduwhv/testing-dev-log/releases/download/1.3.1/crypto-layout-utils-1.3.1.tgz

We downloaded the tarball. The code inside was heavily obfuscated using jsjiami.com.v7, making analysis significantly harder.

Heavily obfuscated malicious code

Exfiltration Payload

After deobfuscating, we confirmed this was a malicious npm package. The attacker had implemented logic inside crypto-layout-utils-1.3.1 to scan the victim’s filesystem — hunting for wallets, private keys, or mnemonic phrases — and upload anything matching to their server githubshadow.xyz.

Deobfuscated code snippet

The package’s file-scanning logic:

File scanning logic

The upload logic for files containing private keys:

Private key upload logic

Attacker Profile

We continued mapping out the operation. The repo owner zldp2002 appeared to control a network of GitHub accounts, used to fork the malicious project, inflate Star and Fork counts, and widen distribution.

Fork network of malicious repos

We also identified multiple forks with similar malicious behavior, some using a different package: bs58-encrypt-utils-1.0.3.

Malicious package timeline

The earliest malicious package, bs58-encrypt-utils, was created on June 12, 2025 — suggesting the campaign had been running since then. After npm took it down, the attacker pivoted to the package-lock.json resolved-field hijack with crypto-layout-utils — an evolution from publishing directly on the registry to smuggling the payload through lockfile tampering.

Additionally, using our on-chain AML and tracking tool MistTrack, we traced one attacker address laundering stolen funds through the instant exchange FixedFloat.

MistTrack trace result

Attack & Defense

From the attacker’s perspective, this was a well-orchestrated operation:

  • Trust hijacking: Exploiting GitHub’s social trust by batch-forking and padding metrics to create an illusion of legitimacy
  • Supply chain poisoning: Avoiding npm’s scanning by never publishing to the registry — instead hijacking the resolved field in package-lock.json, a tiny change easy to miss during code review
  • Code obfuscation: Using the commercial obfuscator jsjiami.com.v7 to slow down static analysis (it didn’t stop us, but it raises the cost for defenders)
  • Asset laundering: Routing funds through FixedFloat and similar non-KYC instant exchanges

From the defensive side, there are clear detection signals:

  • A resolved field in package-lock.json pointing to anything other than the npm registry is a strong indicator
  • Project maintainers controlling a cluster of suspicious GitHub accounts — identifiable through commit timing, naming patterns, and avatar consistency
  • Dependency packages with creation dates and download counts that don’t match — malicious packages often have near-zero downloads despite appearing across multiple projects

My Assessment

This is a textbook consistency gap attack. The attacker exploited two gaps simultaneously: the gap between developers’ trust in GitHub social metrics (Stars/Forks) and a project’s actual security posture, and the gap between developers’ assumption that package-lock.json is auto-generated-and-therefore-trustworthy and the reality that the resolved field can be arbitrarily overwritten.

Two specific gaps:

  1. The “more Stars = safer” perception gap. Stars and Forks can be scripted in bulk. But when developers see high Star counts, they instinctively lower their guard.
  2. The “lockfile = auto-generated = trusted” assumption gap. package-lock.json is produced by npm install — it looks like machine output. Most people never check the resolved field.

A few practical takeaways:

For developers:

  • Before running any open-source project that touches wallets or private keys, at least glance at package-lock.json for resolved fields pointing outside the npm registry
  • Debug unfamiliar projects in an isolated sandbox with no sensitive data
  • Stars are not a security metric

For users:

  • If you suspect your keys have been leaked, don’t hesitate — create a new wallet and move remaining assets immediately
  • Wallet private keys and mnemonic phrases should never live in any directory accessible to Node.js scripts

Malicious Dependency Information

Malicious GitHub repositories (29):

  • 2723799947qq2022/solana-pumpfun-bot
  • 2kwkkk/solana-pumpfun-bot
  • 790659193qqch/solana-pumpfun-bot
  • 7arlystar/solana-pumpfun-bot
  • 918715c83/solana-pumpfun-bot
  • AmirhBeigi7zch6f/solana-pumpfun-bot
  • asmaamohamed0264/solana-pumpfun-bot
  • bog-us/solana-pumpfun-bot
  • edparker89/solana-pumpfun-bot
  • ii4272/solana-pumpfun-bot
  • ijtye/solana-pumpfun-bot
  • iwanjunaids/solana-pumpfun-bot
  • janmalece/solana-pumpfun-bot
  • kay2x4/solana-pumpfun-bot
  • lan666as2dfur/solana-pumpfun-bot
  • loveccat/solana-pumpfun-bot
  • lukgria/solana-pumpfun-bot
  • mdemetrial26rvk9w/solana-pumpfun-bot
  • oumengwas/solana-pumpfun-bot
  • pangxingwaxg/solana-pumpfun-bot
  • Rain-Rave5/solana-pumpfun-bot
  • wc64561673347375/solana-pumpfun-bot
  • wj6942/solana-pumpfun-bot
  • xnaotutu77765/solana-pumpfun-bot
  • yvagSirKt/solana-pumpfun-bot
  • VictorVelea/solana-copy-bot
  • Morning-Star213/Solana-pumpfun-bot
  • warp-zara/solana-trading-bot
  • harshith-eth/quant-bot

Malicious npm packages:

  • crypto-layout-utils
  • bs58-encrypt-utils

Malicious package download URL:

https://github.com/sjaduwhv/testing-dev-log/releases/download/1.3.1/crypto-layout-utils-1.3.1.tgz

C2 exfiltration server:

githubshadow[.]xyz