```html ``` The AsyncAPI Malware Hid Its Payload on IPFS to Be Takedown-Proof. IPFS Isn't Anonymous — Here's the Host Serving It Right Now.
top of page

The AsyncAPI Malware Hid Its Payload on IPFS to Be Takedown-Proof. IPFS Isn't Anonymous — Here's the Host Serving It Right Now.

  • Writer: Patrick Duggan
    Patrick Duggan
  • 32 minutes ago
  • 5 min read

On July 14, an attacker published malware into the @asyncapi namespace on npm — five poisoned versions across four packages that pull more than two million downloads a week. The interesting part is not that it happened. Supply-chain compromises happen weekly, and we cover them weekly. The interesting part is what the attacker did not need to do, and where they hid the payload once they were in. On the second point, we have a receipt most write-ups do not, because we built the tool for it in July.



They Didn't Steal a Token. They Let the Real Pipeline Publish for Them.


Here is the move that should worry you more than the malware. The attacker did not steal an npm publish token. They got push access to the project's own next branch, then opened dozens of pull requests at once to create noise, and buried one real one — PR #2155 — that exploited a known class of GitHub Actions misconfiguration. When that malicious code merged, the project's legitimate release workflow did the publishing. The poisoned packages went out through AsyncAPI's real CI/CD and carried valid SLSA provenance attestations.


Valid provenance. The thing the entire software-supply-chain industry has spent two years selling as the fix. A package that says, cryptographically, "I was built by the real project's real pipeline from the real source" — and it was, and it was malicious, because the source was compromised one commit upstream of the build. Provenance proves origin. It does not prove intent. A trusted pipeline fed a poisoned commit produces a perfectly-attested poison.


We will be honest about our own gap here, because a ledger that only shows wins is a marketing document. We ship a free tool called check-package that an AI coding agent can call to ask whether a dependency is on our known-malicious deny-list before it installs. It would not have caught these at publish time. The packages were legitimately signed by the real project. A deny-list catches known-bad; it does not catch a valid signature on a freshly-subverted trusted package. We are strong on where this payload went and what it does. We are not going to pretend we would have blocked the install in the first sixty seconds.



The Payload Runs on Load, Not Install — Which Is the Whole Point


The malware is a three-stage dropper delivering a RAT the researchers are calling Miasma — a family name that is already in our hunt signatures, because we have been watching for this class in our daily GitHub sweep for weeks. Miasma v3 is a 3-megabyte bundled Node runtime that harvests credentials across 130-plus file types: browser passwords and cookies from Chrome, Brave, Firefox and Edge, SSH keys, npm and GitHub tokens, AWS credentials, the macOS Keychain, and cryptocurrency wallets. It is an info-stealer, a crypto-stealer, and a remote-access trojan in one, and it phones home over six independent channels.


And critically, it does not run from an install hook. It runs when Node loads the infected module. We wrote a whole post in June about Phantom Gyp walking around the standard advice — run with ignore-scripts to block preinstall and postinstall hooks — and this is the same evolution. If your defense is disabling install scripts, this class of malware does not care, because it waits for your application to require the package and executes then. Load-time execution is the new normal, and ignore-scripts is a seatbelt for a crash that already stopped happening.



IPFS Isn't Anonymous. Here Is the Host.


Now the part that is ours.


The first stage does not carry the real malware. It reaches out and pulls an encrypted second stage from IPFS — the InterPlanetary File System, the distributed content-addressed network — using two content identifiers. Attackers love IPFS for payload delivery because there is no single server to seize. You cannot send a takedown notice to a content hash. The content is wherever anyone is willing to host it, addressed by what it is rather than where it is. It reads as takedown-proof.


It is not anonymous, though, and that distinction is the entire game. To download content from IPFS, some node has to be announcing that it has that content and telling the network where to reach it. Those announcements are public. Ask the network who is serving a given hash and it will tell you — an IP address, right now, live.


So we asked. Both malicious content identifiers in this campaign — the generator payload at QmQobZSp1wRPrpSEQ56qnyq7ecZh5Bg5k1fnjt4SUwwHb9 and the specs payload at Qmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyf — resolve to the same provider. A single node, one libp2p peer identity, announcing both, reachable at 69.62.115.175 over IPv4 and at an IPv6 address in the same hosting block. That is the machine serving Miasma to every infected AsyncAPI install that reaches out for its second stage. The takedown-proof payload has a street address.


This is not a clever one-off. It is the exact job of a collector we stood up in July: take a known-malicious IPFS hash, resolve it through the network's own routing to the live host currently serving it, and turn a hash you cannot subpoena into an IP you can block. IPFS solved hosting durability for the attacker and handed us the host in the same protocol. We did that resolution live for this post. It took one request.



The C2, and the Neighborhood It Lives In


The malware's command-and-control is plain old HTTP at 85.137.53.71, across three ports — commands on 8080, upload on 8081, proxy management on 8091 — with a beacon path that gives it away. That address was in our feed within hours of the disclosure, sourced from the researcher who found the campaign. We did not beat him to it and we are not going to claim we did.


What our corpus adds is the neighborhood. That C2 sits in an address block we already know is dirty: our index has botnet command-and-control, Vidar, and Amadey stealer infrastructure clustered in the same 85.137 space going back to February. This is not a fresh box on clean space. It is another tenant in a building we have been flagging for months. When the new C2 for a July campaign lands two doors down from Vidar infrastructure we indexed in the winter, that is not coincidence — that is a hosting choice, and hosting choices are attribution surface.



What To Do Tonight


If you install anything from the AsyncAPI generator toolchain, check your lock files and your CI cache for the poisoned versions: generator 3.3.1, generator-helpers 1.1.1, generator-components 0.7.1, and specs 6.11.2 and 6.11.2-alpha.1. All five have been unpublished from npm, but unpublishing does not reach into a machine that already pulled them. If any of those versions touched a build in the window, treat it as a credential-exposure incident, not a dependency bump — Miasma's first act is to steal every token on the box, so rotate npm, GitHub, AWS, and SSH credentials and assume browser sessions and wallets were read.


Block the infrastructure: the C2 at 85.137.53.71 and the IPFS host at 69.62.115.175. The decrypted final payload hashes to 9e214f38537e69bf51c7fa1ddd35ae495e9cb897231ec010baf9e4f29407ee9a if you want to hunt for it on disk.


And take the provenance lesson seriously, because it is the one that outlasts this campaign. Attestation tells you a package came from the pipeline it claims. It cannot tell you the pipeline was not compromised one commit before the build ran. The defensive weight has to sit on the branch, the merge, and the CI permissions — the place the poison actually enters — not only on the signature at the end. A valid signature on malicious code is still malicious code. It just has better paperwork.




Every indicator in this post is in the feed. Free.

1.58M+ IOCs, STIX 2.1 / TAXII, 88% novel vs ThreatFox, exploited-CVE leads ahead of CISA. No credit card — a free API key in 30 seconds, and you can audit every claim above against the live endpoints.


bottom of page