Ten malicious OpenAPI React Query Codegen releases ran on install and carried credential-stealing code with valid provenance. Teams must scope lockfiles, rebuild hosts and rotate credentials.2026-09-07T14:34:58.323Z5 min2026appsecthreats
5 min read
Read format

Compromised npm Code Generator Steals Developer and Cloud Credentials

Ten malicious OpenAPI React Query Codegen releases ran on install and carried credential-stealing code with valid provenance. Teams must scope lockfiles, rebuild hosts and rotate credentials.

By Justin Howe
A torn white software parcel releases a dark data cable beside a laptop and build server

Ten malicious versions of @7nohe/openapi-react-query-codegen carried valid npm provenance while executing credential-stealing code during installation. The Socket Threat Research Team found releases across every maintained line, putting developer workstations and continuous-integration runners in the incident-response boundary.

Socket published the research on August 28, and its report includes no separate statement from the package maintainer. On September 7, npm registry metadata put the latest tag back on known-good version 3.0.2. The work remains actionable because changing a registry tag cannot clean a machine that already ran a malicious release, erase persistence or revoke credentials the payload could reach. The package draws roughly 150,000 weekly downloads across all versions, though Socket did not quantify affected installations.

Trusted Workflow Published Fork Code

The publishing weakness sat in .github/workflows/release.yml. An issue_comment event started a release when a pull-request comment contained npm publish. The job checked out the pull request’s fork, installed its dependencies and ran pnpm publish --no-git-checks while holding id-token: write.

The workflow checked the comment text but never checked github.event.comment.author_association. Any GitHub account could therefore place code in a fork, open a pull request and invoke the trusted publishing job with one comment.

The provenance record still named the legitimate workflow, refs/heads/main and clean commit d42d1733. Socket captured the boundary in one sentence: “Provenance proves which workflow built an artifact; it does not prove that the workflow only builds trusted source.” npm audit signatures verifies these attestations and therefore does not identify the tainted releases.

That makes this a trust-policy failure inside the publisher. The package registry accepted correctly issued evidence about a workflow that had been allowed to build untrusted input.

Install Triggers Hid Twice

The first wave used binding.gyp, even though the package had no native implementation. Its condition hid a Python object-traversal expression that reached os.system() and ran node 3FWCvzduYZg.js during the native-build path.

Later releases kept that route and added a preinstall entry for the same command. Two prereleases used separate loaders: one fetched Bun 1.4.0 and ran is_it_this_simple.js; another ran nu.js directly. Both carried WORKFLOW_ID=release.yml, REPO_ID_SUFFIX=7nohe/openapi-react-query-codegen and TARGET_PACKAGES=@7nohe/openapi-react-query-codegen.

The 5.6 MB 3FWCvzduYZg.js loader decrypted an AES-128-GCM second stage, wrote it under a random temporary filename, executed it with child_process.execSync and then unlinked it. Socket recovered code for file and process-memory scanning, cloud metadata access, credential validation, encrypted collection, package poisoning, workflow changes, developer-tool persistence, signed remote commands and SSH propagation.

Socket distinguished staged and executed evidence. The malicious loader was configured to execute during installation. Researchers analyzed the package archives and decrypted code statically; they said they did not execute the JavaScript payload, Bun binary, shell modules or Python modules.

Two three-step paths show untrusted fork publishing and install-time credential access

Figure details The diagram follows two ordered three-step paths separated by the registry-to-host trust boundary. An untrusted account comments on a pull request. The release workflow checks out fork code while holding an identity token. npm issues valid provenance and publishes the tainted package. A developer or CI runner installs it, activating binding.gyp or the preinstall command. The recovered second stage then searches for credentials and establishes persistence.

Hunt the Installed Evidence

Start with dependency state. Search lockfiles, software bills of materials and cached package metadata for the ten affected versions:

@7nohe/openapi-react-query-codegen
0.0.0-365d4eb738d3146583431948d3ba6e27a32556be
0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab
0.5.4  0.5.5
1.6.3  1.6.4
2.2.1  2.2.2
3.0.3  3.0.4

Run npm ls @7nohe/openapi-react-query-codegen in each application tree. The last known-good releases are 0.5.3, 1.6.2, 2.2.0 and 3.0.2 for their respective lines.

On systems that installed an affected build, search for these files and persistence paths:

3FWCvzduYZg.js
binding.gyp
ai_init.js
ai_setup.sh
is_it_this_simple.js
~/.local/bin/sysvinit-detect-fash.sh
~/.config/sysvinit-detect-fash/fox
~/.config/sysvinit-detect-fash/fash-detected
~/.config/sysvinit-detect-fash/runit
~/Library/LaunchAgents/com.user.sysvinit-detect-fash.plist
~/.config/systemd/user/sysvinit-detect-fash.service
/var/tmp/.shit
/tmp/.sshu-<random>
/tmp/pcfg/
.config/index.js
.github/_index.js

Hash matches add stronger evidence. Socket published SHA-256 values b49afb7dba04cd99b357ce7c652c823a3707f28e130bd5c6645851a7adc030d6 and 59370c67b54a0ccaedd265e2356f04540b2fba1e1845300ef6de4d5437d99380 for 3FWCvzduYZg.js, plus d3246926b20a8d021ed7de0ac8e9eee1dda986088f84ba18f31cb2042a121f5d for binding.gyp.

The staging account used the GitHub username p00paboot, and its fork was the openapi-react-query-codegen repository under that account. Malicious commit 365d4eb738d3146583431948d3ba6e27a32556be is part of the published chain. These names identify attacker-controlled material hosted on GitHub’s legitimate shared service without providing an acquisition path. GitHub, npm, PyPI, RubyGems, JFrog, Sigstore, Microsoft cloud APIs and cloud metadata services were also used or queried by the recovered payload; their ordinary service endpoints are not standalone block indicators.

Contain Before Rotating Secrets

Treat an affected install as host compromise. Isolate the developer machine or runner, preserve volatile evidence and neutralize the token monitor and other persistence. Rebuild from a known-clean image where practical.

Only after containment should responders revoke and rotate credentials. The recovered monitor polled https://api.github.com/user and executed a stored handler after a GitHub token began returning a 4xx response. Rotating that token while the monitor is still active can trigger the handler.

The rotation boundary includes GitHub, npm, cloud providers, package registries, CI systems and developer tools available to the process. Review new public repositories, workflow edits, dependency-update commits, deployment activity and packages published by identities reachable from the affected host. Socket found code capable of poisoning writable npm, JFrog and RubyGems packages, with optional PyPI typosquatting.

For publishers, require a trusted contributor association before any comment-triggered job receives id-token: write. A safer design separates external pull-request testing from release authority so fork content cannot reach the publishing identity.

Prove Recovery From Lockfiles

Clear package-manager caches, remove existing node_modules, pin the appropriate known-good version and reinstall from a clean lockfile. Then rerun npm ls @7nohe/openapi-react-query-codegen and search the rebuilt host for the listed files, hashes, services and LaunchAgent.

The expected result is one known-good package version, no affected version in any direct or transitive dependency tree, no persistence artifact and no unexplained release or repository activity from rotated identities. A clean dependency listing alone cannot attest to the machine that previously executed the loader; recovery joins dependency state, host evidence and credential history.

Primary sources

Continue reading

Article figurePinch or double-tap to zoom, then drag to pan.