Skip to content
nulltapE-reader edition

← All e-reader articles

5 min read

Poisoned AsyncAPI Packages Ran Code When Developers Imported Them

Five poisoned releases avoided install hooks, launching a detached Node.js process when developer or CI tooling loaded the affected module.

Read on the standard site

Five kraft parcels enter a build machine while a concealed cable trails from one torn package.

Five malicious releases in the @asyncapi npm namespace were built to execute when normal application or build code imported them. They did not rely on preinstall, postinstall or another npm lifecycle hook.

Socket identified the poisoned packages on July 14, 2026. The affected releases were:

The injected code launched a detached Node.js process and fetched a larger payload from IPFS. Because the trigger lived inside ordinary package files, the first malicious execution could occur during an AsyncAPI generator job, a test or a documentation build. A developer workstation could also run it when local tooling loaded the module.

That behavior changes the exposure check. A lockfile can confirm that the package entered the dependency tree, while actual execution depends on whether a process imported the infected file. Responders also need to establish what authority was available on that host at the time.

The import launched the first stage

Socket found a small obfuscated statement inserted into one runtime file in each package. The exact path varied by release. The generator packages carried the code in utilities or template validation logic, while both @asyncapi/specs releases placed it at the top of index.js.

When the affected file loaded, the implant spawned node -e as a hidden background process. Standard input and output were disconnected so the legitimate program could continue without exposing the child process in its normal console output.

The child downloaded sync.js from IPFS and stored it under a directory named NodeJS in the current user’s application-data location. Socket documented paths for Windows, macOS and Linux. The downloaded file contained an encrypted multi-megabyte payload that the researchers identified as a Miasma-family tasking framework.

A poisoned npm release executes during a normal module import, retrieves a payload from IPFS and reaches a developer or CI runner.

Miasma reached beyond the package directory

Socket’s analysis found working handlers for file access, shell execution, payload replacement and beacon timing. The recovered configuration also contained a REST command channel and code for several other communications methods. Some of those additional channels were present but disabled, so they should be treated as capability in the recovered code rather than evidence of active use.

Safe dynamic testing showed the persistence writer attempting to create a Linux user service named miasma-monitor.service. The payload also referenced state beneath .config/.miasma and a camouflaged path under .cache/mesa_shader_cache.

Those artifacts explain why deleting node_modules is an incomplete response. If the import occurred, the second stage may already be running outside the project directory. A compromised CI runner could expose source-control tokens, package publishing credentials or cloud access. A developer machine may place additional SSH material and authenticated browser sessions within reach.

The affected host therefore deserves endpoint investigation alongside dependency cleanup.

Valid provenance traced a poisoned build

The packages were published through the AsyncAPI project’s legitimate GitHub Actions workflow using npm trusted publishing. Their provenance records identified the repository, branch, workflow and source commit that produced the artifacts.

Socket and StepSecurity traced the generator releases to commit 3eab3ec9304aa26081358330491d3cfeb55cc245 on the next branch. The commit contained the injected code and used placeholder author details. StepSecurity concluded that the attacker had gained push access to the branch and allowed the existing release workflow to publish the packages.

The valid provenance was useful evidence. It connected the npm artifacts to the exact source and automation path. It could not establish that maintainers intended the change or that the source commit was safe.

Teams using trusted publishing should keep it. It avoids storing a long-lived npm token in CI and gives investigators stronger build records. The AsyncAPI incident exposes the other half of the design: release authority also depends on who can update a publishable branch and whether the workflow requires an independent approval before it sends an artifact to the registry.

Confirm execution before closing the incident

Start by searching repositories, lockfiles and package caches for the five affected releases. Record every host or runner that might have used them during the exposure window.

Then determine whether the infected file loaded. Process telemetry may reveal a package-driven node -e child, particularly one started in the background with no attached streams. Network records can show an unexpected request to an IPFS gateway during a generator or build job. File and service telemetry can identify sync.js, Miasma state directories or the user-level systemd service.

If execution cannot be ruled out, replace the runner from a clean image or investigate the workstation as a potentially compromised endpoint. Rotate credentials according to what the process could actually access. That assessment should include repository and package tokens, cloud identities and deployment credentials available to the job.

Review outbound access as part of the rebuild. Many CI jobs do not need unrestricted internet connectivity after dependencies are acquired. Network policy can prevent a poisoned module from fetching its next stage even when the initial package reaches the runner.

Release workflows need similar attention. Restrict publishing to protected branches and use an environment that requires review. Alert when an unfamiliar commit identity appears on a release-capable branch. A provenance record should be checked against the expected repository, ref and workflow instead of treated as a universal safety badge.

Install-script blocking remains useful against packages that abuse lifecycle hooks. It would not have stopped these AsyncAPI releases once a trusted tool imported them. Dependency response has to follow the code to the moment it executed and account for the machine that gave it authority.

Close the incident only after affected versions are removed, execution is ruled out or every exposed host is rebuilt, persistence checks are clean and credentials available to the importing process have been replaced.

Primary sources