@subql/common@5.8.3 (SubQuery, the web3 indexing framework; 18k-star monorepo) shipped a postinstall + on-import credential stealer and remote shell on 2026-10-05 — harvests .npmrc, .env, SSH, cloud, Kubernetes, Vault and AI-agent config files, reads the GitHub Actions runner process for tokens, and pushes a disguised CodeQL workflow to dump repository secrets; 19 of 77 @subql packages resolve to it; removed from the registry within hours
TL;DR
On 2026-10-05 at 11:56 UTC a new version of @subql/common — the shared library under SubQuery's indexing CLI, node and query packages — was published to npm as 5.8.3, 32 minutes after a pre-release 5.8.3-onf-rt1 under a dist-tag named redteam. StepSecurity's analysis of 5.8.3, published the same day, says the version adds a postinstall hook and a 62 KB dist/project/readers/manifest-cache.js that is also exported from index.js, so the payload runs on install and again on every import, in a detached child process. Decoded, it collects .npmrc, .env, AWS/GCP/Azure credentials, SSH keys, kubeconfig, Vault tokens, cryptocurrency wallet paths and AI-agent configuration files; on Linux CI it reads the GitHub Actions runner process for the job token, uses stolen GitHub tokens to push a branch carrying a .github/workflows/codeql_analysis.yml that dumps repository secrets to an artifact, and opens a remote shell. By the time this sweep queried the registry the version was gone (version not found: 5.8.3), latest pointed back at 5.8.2, and the redteam pre-release was still listed. If you installed any @subql package between roughly 11:56 UTC and the removal, treat the machine or runner as compromised, rotate everything it could read, and check your repositories for a CodeQL workflow you did not write. Status is unconfirmed because the only analysis is StepSecurity's and SubQuery had not responded on the issue when this sweep read it; the registry removal is the one independent signal.
What happened
- The package.
@subql/commonis the shared types-and-readers library that@subql/cli,@subql/node-core,@subql/queryand the chain-specific node packages depend on. Thesubquery/subqlmonorepo has ~18k GitHub stars (per the Hacker News submission); the package itself had 4,380 downloads in the week ending 10-04, with@subql/cliat 2,374 and@subql/node-coreat 2,011 — a web3 developer audience, not a general one, but one that runs the CLI in CI and holds chain RPC keys, deployer keys and cloud credentials. - The publication. The registry's
timefield shows5.8.3-onf-rt1at 11:24 UTC and5.8.3at 11:56 UTC on 2026-10-05; the previous release, 5.8.2, was 2025-11-20. The pre-release carries aredteamdist-tag. No source this sweep read explains the pre-release, the tag name or who published either version; StepSecurity's issue asks the maintainers to "investigate commit 506863d and the release workflow for unauthorized modifications" and to "rotate npm trusted-publisher settings and all CI secrets," which is the shape of a publish-pipeline compromise, but that is the reporter's request, not a finding. - The payload (StepSecurity's analysis). 5.8.3 adds a
postinstallscript, a newdist/project/readers/manifest-cache.js(62,124 bytes) and a one-line export of it fromindex.js. The file unwraps three layers (base64/XOR, PBKDF2-HMAC-SHA256, AES-256-GCM) into an ~83 KB bundle that: harvests environment variables andgh auth tokenoutput; reads.npmrc,.env, SSH keys, AWS/GCP/Azure credential files, kubeconfig and Kubernetes service-account tokens, HashiCorp Vault tokens, wallet directories and AI-agent configuration files; on Linux runners reads theRunner.Workerprocess memory for the GitHub Actions job token; uses any GitHub token it finds to push a branch containing.github/workflows/codeql_analysis.ymlthat writes the repository's secrets to a workflow artifact; encrypts the collection (RSA-OAEP + AES-256-GCM) and posts it to a command-and-control host; and keeps a channel open for shell command execution and interactive PTY sessions. Because it runs fromindex.jsas well as frompostinstall,--ignore-scriptsdoes not prevent execution — the firstrequire('@subql/common')does. - Blast radius. StepSecurity reviewed 77
@subqlpackages and found 19 whose latest version had a dependency path to@subql/common@5.8.3— 16 directly (including@subql/cli@6.6.3,@subql/node-core@19.3.1,@subql/query@2.25.0) and three through an intermediate package. A floating^5.8.2range resolved to the malicious version for the window it was live. - Takedown. As of this sweep's registry query (2026-10-05, afternoon UTC)
registry.npmjs.org/@subql/common/5.8.3returnsversion not found,dist-tags.latestis5.8.2, and5.8.3-onf-rt1is still listed underredteamwith its own tarball. Who removed 5.8.3 — npm, or the maintainers — is not stated anywhere this sweep could read. The GitHub issue (subquery/subql #3047, opened by a StepSecurity engineer) had no maintainer reply at fetch time.
The pattern. This is the Shai-Hulud/ChainDrop family's tradecraft on a smaller package: runner-memory token theft, a workflow pushed under a plausible security-tool name to exfiltrate secrets through artifacts, and the AI-agent config directories added to the harvest list — SafeDep's 2026-10-02 reading of Google Cloud's AI Risk and Resilience Report says the Shai-Hulud family now searches 469 credential locations, up from 189, with AI tool settings files among the additions (see the Mandiant case study for the report itself). The on-import execution path is the part a defender most often misses: a lockfile that pinned 5.8.3 during the window keeps re-running the payload on every process start until it is changed.
Am I affected?
# Did the malicious version land in any lockfile or node_modules?
grep -rn '"@subql/common"' package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null | grep -n '5\.8\.3'
find . -path '*/node_modules/@subql/common/package.json' -exec grep -H '"version"' {} \;
# The payload file is the tell (absent in 5.8.2)
find . -path '*/node_modules/@subql/common/dist/project/readers/manifest-cache.js'
# CI: any run of a @subql install on 2026-10-05 after 11:24 UTC on a runner with a GITHUB_TOKEN
# Repos: a workflow you did not write
git log --all --diff-filter=A -- .github/workflows/codeql_analysis.yml
Any hit on 5.8.3 or 5.8.3-onf-rt1, or the manifest-cache.js file, means the payload executed on that machine or runner.
If you are affected
- Remove
node_modules, pin@subql/commonto5.8.2(or whatever the maintainers publish as the clean successor) and reinstall from a clean checkout. Rebuild CI runners and any container image that installed during the window from trusted bases. - Rotate everything the payload lists: npm tokens (
.npmrc),.envsecrets, SSH keys, AWS/GCP/Azure credentials, kubeconfig and service-account tokens, Vault tokens, GitHub PATs andghCLI tokens, and any API keys stored in AI-agent configuration directories (~/.claude,~/.codex,~/.cursor, MCP configs) — rotating-cloud-credentials.md, if-your-github-pat-leaked.md, if-your-npm-token-leaked.md. - In every repository a compromised token could push to: delete unexpected branches and any
codeql_analysis.ymlyou did not author, delete workflow artifacts from those runs, rotate repository and organisation secrets, and audit the Actions log for runs you did not trigger — prevention/ci-cd-hardening.md. - Treat the host as having had an interactive shell: review outbound connections from the install window, and follow if-you-ran-malicious-postinstall.md.
Prevention
- Pin exact versions and commit lockfiles; a floating
^range is what resolved to 5.8.3. A cooldown rule (do not adopt a version published in the last N days) would have skipped a 32-minute-old release. --ignore-scriptsis necessary but not sufficient against on-import payloads; combine it with install-time scanning (StepSecurity's, Socket's or Aikido's) and run installs in CI on runners with no ambient cloud credentials — prevention/npm-hardening.md, prevention/package-vetting-checklist.md.- Keep AI-agent configuration out of the credential blast radius: API keys in the OS keychain or a secrets manager, not in
~/.claude/settings.json-style files, since those directories are now on the harvest list of every major stealer family — prevention/credential-hygiene.md. - Alert on new workflow files pushed by a token rather than a person, and on artifacts larger than your builds produce.
Why this matters for vibe coders
A web3 indexer is not a vibe-coding tool, but the payload's harvest list is a snapshot of what attackers now expect to find on a developer machine in 2026: cloud and registry credentials, and the agent config files that hold model-provider keys and MCP server secrets. Whatever package you install next, assume its postinstall and its first import run with everything in your home directory. If you let an agent run npm install for you, that agent's own credentials are in scope.
Update — 2026-10-06: a second, independent analysis (GMO Flatt Security) confirms the payload and supplies the missing "how" — the attacker had push access to subquery/subql and modified the npm publish workflow, so 5.8.3 was built and signed by the project's own GitHub Actions OIDC pipeline; timeline 11:24 pre-release → 11:52 malicious commit → 11:56 publish → 12:46 removal; status moves from unconfirmed to contained
GMO Flatt Security Research published its own write-up on 2026-10-06 (the attack is dated 10-05), reaching Hacker News the same morning. It is an independent read of the same tarball, not a repost of StepSecurity's, and it agrees on every technical point this file took from the first analysis — the AWS/GitHub/SSH/Kubernetes/Vault harvest, the AWS SSM Parameter Store and Secrets Manager enumeration "across all regions," the GitHub Actions runner-memory secret extraction, and the injected workflow "disguised as CodeQL analysis." Two things it adds:
- The compromise method. "The attacker obtained push access to the
subquery/subqlGitHub repository and tampered with the CI/CD workflow (.github/workflows/publish.yml) to inject a malicious payload into the legitimate npm publishing flow." The malicious release therefore carries the project's normal trusted-publisher provenance — which is why the 10-05 file could not tell from the registry whether a maintainer or an attacker published it. The malicious commit is 506863d6fb82bd2714970cf8c6f1bf364374b009, the one StepSecurity's issue asked the maintainers to investigate. - The timeline (UTC, 2026-10-05). 11:24
5.8.3-onf-rt1published, with no postinstall script (Flatt calls it a "presumed test release"); 11:52 the malicious commit pushed; 11:565.8.3published via GitHub Actions OIDC; 12:46 package removed from the npm registry. That makes the live window 50 minutes for the malicious version, and it explains theredteam-tagged pre-release the 10-05 file reported without interpreting: it was the dry run.
Flatt also names the command-and-control domain and IP; this file continues not to reproduce them beyond saying that any outbound connection from a build host or runner to the ci-artifacts.dev domain on or after 2026-10-05 is a compromise signal — treat the domain as an IOC in egress logs, not as something to visit.
Status. Two independent analyst firms, a registry removal confirmed by both and by this repo's own query, and a stated compromise method meet this repo's bar; unconfirmed → contained. Still missing at fetch time: any statement from the SubQuery maintainers, and confirmation that the repository's push access and publishing secrets have been rotated — until that appears, treat the @subql namespace as capable of producing another malicious release and keep the pins. The lesson for everyone else is the one Flatt's title implies: with trusted publishing, the publish workflow file is the signing key; protect .github/workflows/publish.yml with required reviews and environment protection rules the same way you would protect an npm token — prevention/ci-cd-hardening.md.
Sources
- StepSecurity — SubQuery Ecosystem Compromise: Hidden Credential Theft and Backdoors — 2026-10-05, the primary analysis: files added in 5.8.3, the three-layer unpacking, the harvest list including AI-agent configs, runner-memory extraction, the CodeQL-named workflow injection, the 77-package / 19-affected dependency review, the on-import execution path. Fetched 2026-10-05.
- subquery/subql issue #3047 — "[security]: Malicious release @subql/common@5.8.3 (postinstall credential stealer)" — opened 2026-10-05 by a StepSecurity engineer; the publish timestamp, the 62,124-byte file, the
index.jsexport, the requested remediation (unpublish, investigate commit 506863d and the release workflow, rotate trusted-publisher settings). No maintainer reply at fetch time (2026-10-05). - npm registry —
@subql/commontimeanddist-tags— queried 2026-10-05:5.8.3-onf-rt111:24 UTC,5.8.311:56 UTC,latest→ 5.8.2, dist-tagredteam→ 5.8.3-onf-rt1;/@subql/common/5.8.3returnsversion not found. - npm downloads API —
@subql/common,@subql/cli,@subql/node-core(week ending 2026-10-04) — 4,380 / 2,374 / 2,011. - Hacker News — "Subql/common 5.8.3 compromised: postinstall stealer in 18k-star SubQuery repo" — 2026-10-05 submission linking the issue; the star count.
- SafeDep — An Attacker Hijacked an AI Coding Assistant to Spread a Worm — 2026-10-02, secondary; the 189 → 469 credential-location figure attributed to Google Cloud's AI Risk and Resilience Report 2026. Fetched 2026-10-05.
- Related in this repo: Mandiant hijacked coding-assistant session → Shai-Hulud, ChainDrop / keyv, Mini Shai-Hulud.
- GMO Flatt Security Research — Software Supply Chain Attack on subql/common — 2026-10-06 (attack 2026-10-05), the second independent analysis: push access to
subquery/subql, the tampered.github/workflows/publish.yml, the UTC timeline (11:24 / 11:52 / 11:56 / 12:46), the SSM Parameter Store and Secrets Manager enumeration, commit 506863d. Fetched 2026-10-06. The post names the C2 domain and IP; they are deliberately not linked here. - Hacker News (Algolia) — "Software Supply Chain Attack on subql/common" — 2026-10-06 submission of the Flatt post.