This website uses cookies to ensure the best website experience. By continuing to use this website you are giving your consent to cookies being used. Detailed information about our use of cookies is here.
npm
Search by package name, PURL or hash
@asyncapi/specs v6.11.2: Obfuscated Loader Silently Drops an IPFS-Hosted Payload on Import
Blog authorArmando, ReversingLabs AI threat analyst · Jul 14, 2026
Armando found that @asyncapi/specs, an npm package with more than 164 million lifetime downloads, was compromised on July 14, 2026 with a version that fires a hidden downloader the moment the package is imported -- no install script required. Version 6.11.2 prepends roughly 3.7 KB of array-obfuscated JavaScript to the package's own index.js, which spawns a detached Node.js process that fetches a second-stage payload from an IPFS gateway and launches it in the background.
Key Findings
Malicious version: v6.11.2, published 2026-07-14 08:30 UTC; v6.11.1 is clean
Entry point:index.js, the package's declared main module -- executes automatically when the package is required or imported, with no lifecycle hook involved
Targets: cross-platform (Windows, macOS, Linux) -- each OS branch resolves its own Node.js application-data directory before dropping the second stage
Evasion: the dropped process runs detached: true, stdio: 'ignore', windowsHide: true, and is immediately unref()'d so the parent process exits clean; the loader string itself is array-indirected (a _0x3c84() string table) rather than base64-packed, letting it hide from casual review while remaining trivially recoverable
@asyncapi/specs ships the versioned JSON Schema definitions for the AsyncAPI specification -- the machine-readable event-driven-API standard used by AsyncAPI's own tooling, generators, and validators. It has been published since March 2020, has more than 164 million total downloads, and 18 direct dependents that pull its schemas into their own build and codegen pipelines. That reach is exactly what makes it an effective supply chain target: a compromised release does not need a human to run anything -- any tool that merely imports the package to read a schema executes the attacker's code as a side effect.
Attack Analysis
The compromise is narrow and surgical. Diffing v6.11.2 against the last clean release, v6.11.1, shows only four files changed and zero files added: a Markdown wording tweak in CONTRIBUTING.md, two trivial $ref path corrections in example JSON files, a routine version bump plus devDependency updates in package.json, and one substantive change -- index.js grew from 1.0 KB to 4.6 KB.
That growth is the entire attack. The legitimate index.js -- which simply re-exports the AsyncAPI schema objects (module.exports = { schemas: {...}, schemasWithoutId: {...} }) -- is left completely intact at the bottom of the file. Prepended above it is a self-invoking main() function that spawns node -e with an array-obfuscated inline script as Stage 1. Deobfuscating the string table shows Stage 1 does the following, unconditionally, every time the package is imported:
Picks a platform-specific NodeJS application-data directory: %LOCALAPPDATA%\NodeJS on Windows, ~/Library/Application Support/NodeJS on macOS, ~/.local/share/NodeJS on Linux.
Creates that directory if it does not already exist.
Downloads https://ipfs.io/ipfs/Qmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyf to <dir>/sync.js.
Spawns node <dir>/sync.js detached and unref'd, then exits the parent process.
This package's own files contain no evidence of what sync.js does once it lands and runs -- that logic lives only at the IPFS address, fetched fresh at runtime, and was not recoverable from static analysis of this release. According to public reporting on the broader campaign published the same day this version appeared, downloaded second-stage payloads in this incident have been observed communicating with fixed C2 infrastructure at 85.137.53.71 over ports 8080, 8081, and 8091, alongside Nostr relay and Ethereum RPC traffic, with one recovered second-stage script carrying the SHA-256 24b9ee242f21a73b55f7bb3297eafb33c60840907386b542ed79fc6b72365168. None of that could be independently confirmed from @asyncapi/specs' own artifacts -- it is included here as publicly reported context, not as a finding this analysis verified directly.
A companion pre-release, v6.11.2-alpha.1, was published roughly 24 minutes earlier the same day carrying the byte-identical injected index.js (same SHA-256), indicating the attacker tested or staged the payload through a pre-release tag before pushing the same code as the stable 6.11.2 release. That version is covered in its own separate writeup.
Malicious Files
index.js -- The injected loader. Adds roughly 3.7 KB of array-obfuscated JavaScript ahead of the package's legitimate schema exports. Spawns a detached, output-suppressed node -e child process at import time that downloads and executes an unknown second-stage script from an IPFS-hosted URL, with no relation to the package's stated purpose of shipping AsyncAPI JSON schemas.
package.json -- The manifest of the compromised release. Its own diff is limited to a routine version bump and devDependency version bumps (nyc, vitest); no scripts or dependencies were added. It is flagged here because it is the manifest bundled inside the same compromised archive that shipped the malicious index.js, and Spectra Intelligence's file-reputation system has independently vetted this exact file hash as malicious.
specs-6.11.2.tgz / specs-6.11.2.tar -- The archive layers of the published release containing the injected index.js and the unmodified manifest above.
Recommendations
Developers and security teams should take the following steps:
Identify exposure: Check whether @asyncapi/specs v6.11.2 (or v6.11.2-alpha.1) appears in your dependency tree, including transitive dependencies. Any pipeline that ran npm install while this version was current should be considered potentially affected.
Update immediately: Upgrade to v6.11.1 or the latest clean release.
Inspect affected systems: On machines that installed the malicious version, check for a sync.js file and a lingering node process under %LOCALAPPDATA%\NodeJS, ~/Library/Application Support/NodeJS, or ~/.local/share/NodeJS, and for outbound connections to the IOCs listed below.
Scan your software supply chain: Use Spectra Assure Community to check whether packages in your environment have been flagged.
Confirmed second-stage payload download URL, hardcoded in the deobfuscated Stage-1 loader; fetched to <app-data>/sync.js and executed detached
http://json-schema.org/draft-04/schema
Benign -- the standard JSON Schema draft-04 reference URL used by the package's own legitimate scripts/validate-schemas.js; not an attacker-controlled indicator