Skip to content

[URGENT] Malicious NPM packages published #217

Closed

Description

@CharlieEriksen

Hi,

A few malicious npm packages were published of the package @7nohe/openapi-react-query-codegen, versions:

  • 1.6.3
  • 3.0.3
  • 2.2.1
  • 0.0.0-365d4eb738d3146583431948d3ba6e27a32556be

They all contain to contain malicious binding.gyp files, and an obfuscated word.

Best regards,
Charlie

Activity

  1. LewisArdern commented on Aug 28, 2026

    @LewisArdern

    @CharlieEriksen i think they have an issue with their github action publish step that allows for anyone to push arbitrary versions out when including npm publish in a pull req comment:

    jobs:
      release:
        if: ${{ github.event_name == 'push' || (github.event.issue.pull_request && github.event.comment.body == 'npm publish') }}
    
  2. 7nohe commented on Aug 28, 2026

    @7nohe
    Owner

    Thank you for the report, @CharlieEriksen — it is accurate, and the scope is larger than the four versions listed.

    Confirmed malicious versions (10)

    0.5.4, 0.5.5, 1.6.3, 1.6.4, 2.2.1, 2.2.2, 3.0.3, 3.0.4,
    0.0.0-365d4eb738d3146583431948d3ba6e27a32556be,
    0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab

    All were published on 2026-08-28 between 20:00 and 20:21 UTC. Each contains a
    binding.gyp crafted to execute an obfuscated payload (3FWCvzduYZg.js, 4.4-6.4
    MB, a different build per version) through node-gyp.

    Six of the ten additionally carry an explicit "preinstall": "node 3FWCvzduYZg.js". Four do not - 0.5.4, 1.6.3, 2.2.1 and 3.0.3 have no
    install script at all and rely on binding.gyp alone. If you are scanning
    lockfiles or caches, match on the presence of binding.gyp or 3FWCvzduYZg.js
    in this package, not on install hooks, or you will miss those four.

    latest pointed at the malicious 3.0.4 during this window.

    No version published before 2026-08-28 is affected. 3.0.2 and earlier are
    clean, as is the beta dist-tag.

    Root cause

    @LewisArdern's diagnosis in this thread is correct. Our release workflow was
    triggered by issue_comment with no author-association gate, so any user could
    start it by commenting npm publish on any pull request. The job then checked
    out the pull request head and ran pnpm install, which executed a preinstall
    script from the attacker's fork inside a job holding id-token: write. That was
    sufficient to mint an npm trusted-publishing token and publish arbitrary
    versions.

    The attacker (@p00paboot) used PRs #215 and #216, then force-pushed both
    branches to remove the malicious commits. The original commits are still
    reachable via refs/pull/215/head and refs/pull/216/head in this repository's
    reflog and confirm the vector.

    Note that @p00paboot also posted the "seems fine to me, stop spreading
    misinformation" comment above. Please disregard it.

    Remediation

    • The issue_comment trigger has been removed; releases now run on tag push
      only (8330895).
    • The npm trusted publisher for this package has been revoked.
    • All long-lived npm tokens have been revoked.
    • latest has been restored to 3.0.2 and the pre dist-tag removed.
    • All ten versions are deprecated with a security notice.

    The malicious tarballs are still resolvable. npm unpublish is permanently
    refused for this package ("has dependent packages in the registry"), and
    deprecation only prints a warning — it does not prevent installation. I have
    filed a removal request with npm security; until they act,
    npm install @7nohe/openapi-react-query-codegen@3.0.4 still succeeds and still
    executes the payload. Please make sure your lockfiles and any pinned versions
    do not reference the versions listed above.

    Note also that these versions carry valid SLSA provenance attestations —
    they were published through my genuine release workflow, so provenance alone
    does not distinguish them from legitimate builds.

    The repository itself was not tampered with — main, all tags, and all GitHub
    Releases are intact and match their pre-incident state.

    If you installed during the affected window

    If you ran an install that resolved to any version above on or after
    2026-08-28 20:00 UTC — including CI runs — the payload executed on that machine.
    Please:

    1. Rotate every credential reachable from that machine or CI runner: npm tokens,
      GitHub tokens and SSH keys, cloud provider keys, and any secrets in the
      environment.
    2. Audit your own npm account for package versions you did not publish, and your
      GitHub account for unexpected repositories, workflow runs, or new SSH keys —
      this class of payload is known to self-propagate through the maintainer
      credentials it steals.
    3. Pin to 3.0.2 or earlier, or reinstall from a clean lockfile once the bad
      versions are removed.

    A GitHub Security Advisory will follow. Apologies to everyone affected, and
    thank you again for the fast disclosure.


    Edited 2026-08-29: corrected the payload description. My original wording said
    all ten versions carry a preinstall hook; only six do, and the other four
    execute via binding.gyp alone. Thanks to @danieldanzigerupwind for catching
    this in #218.

  3. ramimac commented on Aug 28, 2026

    @ramimac

    @7nohe thanks for your prompt and considered response!

  4. 7nohe commented on Aug 28, 2026

    @7nohe
    Owner

    Status update.

    Advisory published

    GHSA-9pvf-vcx3-x239 — CVSS 9.6 (critical), covering all ten versions.

    GHSA-9pvf-vcx3-x239

    Once GitHub completes its review, affected repositories will receive Dependabot
    alerts automatically. That review can take up to three working days, so this
    thread and the advisory remain the fastest source until then.

    Correction to my earlier comment

    I wrote that all ten tarballs carry a preinstall hook. That is not accurate,
    and the detail matters for anyone scanning:

    Version Install script binding.gyp / 3FWCvzduYZg.js
    0.5.4, 1.6.3, 2.2.1, 3.0.3 none present
    0.5.5, 1.6.4, 2.2.2, 3.0.4 preinstall present
    0.0.0-365d4eb…, 0.0.0-ec7876d… preinstall absent

    The four in the first row execute through binding.gyp alone — npm runs
    node-gyp rebuild for a package with no install script, which evaluates the
    crafted conditions block. The two prereleases carry a malicious preinstall
    but not the payload files, because they were packed with the real
    files: ["dist"] field.

    Neither signal alone covers all ten. Match on either the presence of
    binding.gyp / 3FWCvzduYZg.js, or any install hook. Credit to
    @danieldanzigerupwind, who caught the binding.gyp-only cases in #218.

    Still outstanding

    npm has not removed the tarballs. npm unpublish is permanently refused for this
    package ("has dependent packages in the registry"), and deprecation only prints a
    warning — it does not block installation. Until npm acts:

    • npm install @7nohe/openapi-react-query-codegen@3.0.4 still succeeds and still
      executes the payload.
    • Anything pinned or lockfile-resolved to an affected version is still live.

    A plain npm install @7nohe/openapi-react-query-codegen is safe — latest
    resolves to 3.0.2.

    For other maintainers

    The attacker's loader took WORKFLOW_ID, REPO_ID_SUFFIX and TARGET_PACKAGES
    as parameters. It was written to be pointed at any repository with this pattern,
    not at mine specifically. If you have a workflow that can publish and triggers on
    issue_comment — or any event carrying untrusted code into a job with
    id-token: write — please check it.

    I will update this thread when npm removes the versions.

  5. 7nohe commented on Aug 29, 2026

    @7nohe
    Owner

    Resolved: npm has removed all ten versions

    Verified just now — every affected version returns 404 at the registry:

    0.5.4  0.5.5  1.6.3  1.6.4  2.2.1  2.2.2  3.0.3  3.0.4
    0.0.0-365d4eb738d3…    0.0.0-ec7876d6c917…
    

    The package went from 70 published versions to 60. npm view …@3.0.4 now errors,
    and the tarball URLs return HTTP 404. latest resolves to 3.0.2.

    There is no longer any path by which a fresh install pulls the payload.

    If your lockfile pins an affected version

    npm ci will now fail with a 404 rather than installing. That is the safe
    outcome, but the error does not explain itself. If you hit it, update the
    lockfile to 3.0.2 or later:

    npm install @7nohe/openapi-react-query-codegen@latest

    Removal does not undo an install that already happened

    If you installed an affected version on or after 2026-08-28 20:00 UTC, the
    payload executed then and the guidance is unchanged: rotate every credential
    reachable from that machine or CI runner, and audit your own npm and GitHub
    accounts for publishes, repositories, or keys you did not create.

    Final state

    • Root cause removed — the release workflow no longer triggers on
      issue_comment; releases run on tag push only (8330895).
    • npm trusted publisher revoked; all long-lived npm tokens revoked.
    • latest restored to 3.0.2; pre dist-tag removed.
    • All ten versions deprecated, then removed by npm.
    • Advisory published: GHSA-9pvf-vcx3-x239 (CVSS 9.6). Dependabot alerts will
      follow once GitHub completes its review.
    • The attacker account has been reported to GitHub.

    Thank you @CharlieEriksen for the disclosure, which arrived within twenty minutes
    of the first malicious publish, and @LewisArdern for identifying the workflow
    misconfiguration in this thread. Between the two of you the root cause was known
    before I had finished reading the report.

    Closing. Please reopen or file a new issue if anything related surfaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions