# GHAPPIER Loader: npm Supply-Chain Compromise of @dforge-core/dforge-mcp Linked to DPRK PolinRider Campaign

> CloudSEK identified GHAPPIER, a previously unreported four-stage loader delivered through a 105-minute maintainer-account takeover of the npm package @dforge-core/dforge-mcp (malicious v0.2.21, reverted to clean v0.2.22). The malicious release carried valid npm provenance via abused GitHub Actions OIDC trusted publishing, used an Ethereum-blockchain address as its command source, and self-deleted its final implant. Payload and infrastructure overlap ties GHAPPIER to the DPRK-linked PolinRider campaign, which has separately compromised 65+ npm/GitHub repositories in this incident and, cumulatively since March 2026, thousands of repositories across npm, PyPI, Go, Packagist, and Chrome Web Store.

- **Published:** 2026-09-20T00:00:00Z
- **Last reviewed:** 2026-09-20T00:00:00Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-2588
- **ID:** TL-2026-2588
- **Severity:** HIGH
- **Category:** SUPPLY_CHAIN
- **Status:** ACTIVE
- **Actor:** PolinRider (North Korea)
- **Detections:** 9 · **IOCs:** 24 (full data via the Threadlinqs MCP server — Purple tier)

## Description

On 2026-09-09, an attacker held valid push/publish-equivalent access to the @dforge-core/dforge-mcp npm maintainer account for a 105-minute window. Fourteen minutes into that window the GitHub Actions CI workflow was rewritten to auto-publish on push to main without manual review, and a remote-code loader was injected as a single line (line 3320 of a 99KB configuration file) into otherwise-legitimate package source. Version 0.2.21 reached the npm registry and remained the latest release for 35 minutes 38 seconds before the maintainer reverted the account and published a clean v0.2.22. Because the malicious release was built through the repository's legitimate GitHub Actions OIDC trusted-publishing workflow, it carried a genuine npm provenance statement and an authentic Sigstore attestation naming the attacker's own commit -- CloudSEK's central finding is that provenance attests where an artefact was built, not whether its source was honest, so trusted publishing let a single compromised push credential produce a fully 'verified' malicious release.

The payload is a four-stage loader: an initial injected loader in package source, a rewritten CI workflow that forces unattended publishing, the published malicious package itself, and a final implant that deletes itself from disk the instant it executes, leaving no artefact for a post-incident file sweep to find. Instead of a traditional domain- or IP-based C2 channel, the PolinRider-linked payload reads its command source from an Ethereum blockchain wallet address: a twenty-byte recipient address is embedded in an otherwise-empty transaction costing roughly $0.20, giving the operator a C2 channel with no domain to suspend, no host to seize, and no account to disable. CloudSEK reports one socket endpoint and two delivery hostnames tied to the campaign (values withheld from the public blog behind a gated full report) and states that an exact-match sample of the payload was still beaconing as the report was being written, more than five days after the malicious npm version was withdrawn.

This blockchain dead-drop design mirrors -- and CloudSEK cites payload/infrastructure overlap with -- the DPRK-linked PolinRider campaign, tracked publicly since March 2026, which has grown from 675 to over 1,900 GitHub repositories by April 2026 and, per subsequent reporting, expanded across npm, PyPI, Go modules, Packagist, and a Chrome extension (108-111 unique packages, ~160-200 release artifacts) by July 2026, with a further compromised high-download Packagist package (visanduma/nova-two-factor, 700,000+ downloads) disclosed by Socket on 2026-09-17, three days before the GHAPPIER report. PolinRider's own blockchain C2 uses TRON and Aptos (with BNB Smart Chain observed) dead-drop addresses to fetch XOR-encrypted second-stage payloads executed via eval(), delivering RATs and infostealers (DEV#POPPER, OmniStealer) and, per OpenSourceMalware, a variant of the DPRK Beavertail malware family. A closely related technique named NullReceiver (published August 2026) encodes a C2 IP directly in the recipient-address bytes of an Ethereum wallet's most recent outbound transaction -- the same 'address-as-C2' primitive GHAPPIER's payload uses -- and was found in separate npm packages (bianira-ui, fluid-type-ui) tied to the same DPRK developer-targeting cluster (Contagious Interview / Famous Chollima).

CloudSEK is explicit that its North Korea attribution is inherited from NullReceiver researchers rather than independently re-verified, and that 'nothing here evidences a successful compromise of any organisation' downstream of the npm package -- the incident documents a successful supply-chain injection and a live, still-functional payload, not confirmed victim compromise. Because the final implant self-deletes, CloudSEK recommends defenders sweep for the artefacts the chain leaves behind (a rewritten CI workflow, the injected loader line, transient blockchain-RPC network connections) rather than searching for the implant file itself, which will not be there to find.

## MITRE ATT&CK

- T1585 Establish Accounts
- T1587.001 Malware
- T1608 Stage Capabilities
- T1583.001 Domains
- T1195.002 Compromise Software Supply Chain
- T1199 Trusted Relationship
- T1078 Valid Accounts
- T1552.001 Credentials In Files
- T1059.007 JavaScript
- T1027 Obfuscated Files or Information
- T1070.004 File Deletion
- T1140 Deobfuscate/Decode Files or Information
- T1102.002 Bidirectional Communication
- T1071.001 Web Protocols

## Sources

- [GHAPPIER - One loader, sixty-five repositories, twenty-two accounts: an unreported loader family beside DPRK's PolinRider campaign](https://www.cloudsek.com/blog/ghappier-malware-loader-npm-supply-chain-attack)
- [PolinRider (technical dossier)](https://github.com/OpenSourceMalware/PolinRider)
- [PolinRider Campaign: DPRK-Linked Supply Chain Attack Infects GitHub Repositories](https://threats.wiz.io/all-incidents/polinrider-campaign-dprk-linked-supply-chain-attack-infects-github-repositories)
- [Trojanized npm Packages Employ NullReceiver Tactic to Decode C2 IP from Blockchain](https://thehackernews.com/2026/08/trojanized-npm-packages-decode-c2-ip.html)
- [NullReceiver's Blank Crypto Transfers Solves the Challenges of EtherHiding](https://opensourcemalware.com/blog/nullreceiver-dprk-c2-technique)
- [North Korean Hackers Publish 108 Malicious Packages and Extensions in PolinRider Campaign](https://thehackernews.com/2026/07/north-korean-hackers-publish-108.html)
- [PolinRider Jumps the Fence to Go, Packagist, npm, PyPI](https://opensourcemalware.com/blog/polinrider-jumps-the-fence)
- [PolinRider Spreads Through Compromised GitHub Accounts and Packagist](https://socket.dev/blog/polinrider-github-packagist)
- [Week 38 - 2026 digest (GHAPPIER / PolinRider roundup)](https://thisweekin4n6.com/2026/09/20/week-38-2026/)
- [dforge-core/dforge-mcp (legitimate upstream repository)](https://github.com/dforge-core/dforge-mcp)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-2588
