npm’s trusted publishing was supposed to close the supply chain gap for good. Signed packages, short-lived OIDC tokens, Sigstore provenance attestations — the works. Then GHAPPIER happened. A new malware disclosed by CloudSEK on September 20 didn’t forge a single certificate. The attacker stole the maintainer’s account, rewrote the CI workflow, and let GitHub Actions produce a perfectly signed, provenance-attested malicious release on their behalf. The package — @dforge-core/dforge-mcp, a legitimate MCP server — was up for 35 minutes and 38 seconds before anyone noticed. Every signature checked out.
What Happened #
On September 9, 2026, an attacker spent 105 minutes inside the maintainer account of @dforge-core/dforge-mcp. CloudSEK could not establish exactly how access was obtained, but suspects a compromised developer machine — likely an infected extension or package already installed on the maintainer’s system.
The attacker’s first move was surgical: change three lines in the GitHub Actions workflow so any push to the main branch triggered the release pipeline. Fourteen minutes later, they rewrote the workflow to publish without human review. A first malicious release, 0.2.20, failed and broke installation. The second attempt, 0.2.21, shipped the GHAPPIER and sat as the latest version for exactly 35 minutes and 38 seconds.
The itself was one obfuscated line inside a 99KB source file. When triggered, it opened a four-stage chain ending in a general-purpose remote shell that deleted itself from disk while running. Critically, it fired when the MCP server was launched, not when it was installed. Anyone who installed 0.2.21 but never started it didn’t run the payload — a deliberate stealth choice that bypasses install-time scanners.
Why Trusted Publishing Didn’t Help #
This is the part that should worry every developer who breathed a sigh of relief when npm trusted publishing went GA in July 2025. The GHAPPIER package carried valid npm provenance. GitHub Actions generated it using OIDC trusted publishing. The Sigstore attestation recorded the attacker’s commit as a legitimate, signed build from the real repository.
That’s not a bug — it’s how the system is supposed to work. Sigstore and npm provenance verify that a package was built in a specific CI pipeline from a specific repository. They cannot verify that the human who triggered that pipeline intended to ship malicious code. As CloudSEK put it: “Every action was an authorised action taken with a stolen key.”
The security model assumes developer identity is the last line of defense. GHAPPIER proves that assumption is now the attack surface. Provenance attests pipeline identity, not pipeline integrity. A signed package tells you where it came from — nothing about whether the person who sent it meant to harm you.
The Broader Footprint — and a DPRK Link #
The dforge-mcp package was one entry point. CloudSEK traced GHAPPIER across 65 public GitHub repositories, 73 infected files, and 22 accounts. In one victim’s repository, a second payload turned up that exactly matched PolinRider — a supply chain campaign tracked since March 2026 that multiple researchers attribute to North Korea’s Contagious Interview cluster. PolinRider has distributed 108+ malicious packages across npm, Go modules, Packagist, and Chrome extensions.
CloudSEK is appropriately cautious — its own attribution check didn’t independently confirm DPRK involvement — but the payload overlap is documented. Whether GHAPPIER is a DPRK tool or an unrelated actor reusing the same toolkit, the scale is significant. npm supply chain attacks in 2026 are running at 2.6 times the campaign volume of all of 2025, and MCP server packages have emerged as a preferred vector precisely because developers routinely launch them with broad system access.
What You Need to Do Now #
If you use @dforge-core/dforge-mcp, check your lockfile for version 0.2.21. For everyone else, the mitigations are about hardening the CI identity surface:
- Scope CI permissions tightly. Use
permissions: {}at the workflow level and grant onlyid-token: writeandcontents: readto your publish job. - Add environment protection. Configure aGitHub Actions deployment environment for npm publishes and require manual approval — a gate the attacker would have had to defeat separately.
- Require PR reviews before merging to main. If your CI auto-publishes on push to main, a branch protection rule requiring at least one approval limits an attacker’s ability to trigger the release workflow unilaterally.
- Audit your dev machine. The suspected initial vector was an infected extension or package on the maintainer’s system. Review VS Code extensions and globally installed npm packages.
- Pin third-party Actions to commit SHAs. Mutable version tags in publishing workflows are a separate risk; SHA pinning eliminates it.
Each npm security upgrade has prompted a matching adaptation: npm v12 blocked lifecycle scripts, so attackers moved malware into runtime library code. GHAPPIER skipped that problem entirely by going one level upstream — compromise the CI identity and let the registry sign the attack for you. The trust boundary has moved from the package registry to the developer’s machine. That’s a harder perimeter to defend.