A single npm account published 14 rigged packages in about 41 hours, all built around npm dependency confusion. The packages carry names that sound like the internal libraries of real companies, such as @greenlake/auth or @sxm-web/client-sdk-core. Anyone who installs one by mistake sends information about their machine or build server to an outside IP address. GitHub classified all of them as malware on October 26, 2026.
We explain how the attack works, how to spot affected packages and which settings in npm projects and CI pipelines protect against it.
Key Takeaways
- The npm account “wiseke” published 14 packages between October 23 (21:23 UTC) and October 25, 2026 (14:28 UTC) under the scopes
@greenlake,@sxm-web,@drone-js-extand@ppa-web-components. - Each package runs a
postinstallscript on installation and sends the hostname, install path and working directory over plain HTTP to a remote server. - A hidden proxy keeps builds running, so the attack does not surface through errors.
- The packages use inflated version numbers such as 13.3.7 or 99.0.1 so that npm prefers them over internal packages.
- GitHub advises treating affected machines as compromised and rotating all secrets from a different device.
What npm Dependency Confusion Means
Many companies do not publish their own JavaScript libraries on the public npm registry but on a private one, such as Artifactory, Verdaccio or GitHub Packages. If a build is not configured cleanly, npm may also query the public registry for a package name. If a package with the same name and a higher version number exists there, npm can end up installing it instead of the internal one.
That mix-up is called dependency confusion. The attacker only needs to know or guess the name of an internal package and claim it publicly. Internal names leak surprisingly often, for example through accidentally published package.json files, source maps or error messages.
What the 14 Packages Actually Do
The GitHub advisory GHSA-pmfr-35rg-27xm for @greenlake/context-pane describes behavior that is identical across all 14 packages:
- Disguise: the package calls itself a “Compatibility shim”. Its README claims to be an “authorized dependency-confusion test”. That is unverified and comes from the account itself.
- Runs on install: every affected version ships a
postinstallscript that runsnode beacon.cjs. In addition,index.jscalls the same code whenever the package is imported. - Data exfiltration: the script POSTs the hostname, install path and current working directory over unencrypted HTTP to
185.158.107.175on port 8787. An Amazon Inspector analysis recorded in the OSV database (MAL-2026-18319) adds the Node.js version and package name. - No crash:
index.jsexports a JavaScript proxy that returns an empty function for every access. Code expecting the real internal package keeps compiling. - Reused tooling: according to GitHub,
index.jsis byte-identical to the packageph-common(MAL-2026-1809), which reports to the same endpoint.
The version numbers stand out. @sxm-web/client-sdk-core appeared as 13.3.7, among others, while @greenlake/session and @ppa-web-components/ppa-navigation were published as 99.0.1. Jumps like these are meant to make sure the public package outbids any internal version.
How Dangerous Is This?
At first glance the payload looks harmless. It does not steal passwords or tokens, it “only” sends system information. That view is too narrow:
- Reconnaissance: a hit tells the attacker that a specific organization is vulnerable to dependency confusion, which host it happens on and what the directory layout looks like. That is ideal preparation for a second, more dangerous step.
- Swappable payload: once someone gets code into a pipeline via
postinstall, the next version can run anything. - Official rating: GitHub classifies the packages as malware (CWE-506, embedded malicious code) and recommends considering affected systems fully compromised.
It remains unclear whether any real organization actually installed the packages. Neither the advisories nor the npm registry say so. It is also unknown who operates the account and the IP address. The “authorized test” label should be read with caution. A genuine engagement as part of a penetration test would not usually need to hide its network calls like this.
How to Protect Against npm Dependency Confusion
The good news is that a few clear configuration rules defend against this entire class of attack.
- Bind your scope to the private registry: set in
.npmrcthat your internal scope only comes from your own registry, for example@company:registry=https://npm.company.internal/. The npm documentation on scopes explains how this works. - Reserve the scope publicly: create an organization on npmjs.com with the name of your internal scope. Then nobody else can publish packages there.
- Use the lockfile: run
npm ciinstead ofnpm installin CI. That installs only the versions and sources recorded in the lockfile. - Restrict install scripts: the
ignore-scriptsoption stopspostinstallscripts from running automatically. This needs testing, because some legitimate packages rely on scripts. - Limit outbound traffic: build servers rarely need open internet access. An egress rule that only allows your own registry stops beacons like this one.
- Check your logs: search proxy and firewall logs for connections to
185.158.107.175:8787, and lockfiles for the four scopes named above.
If you find a hit, follow GitHub’s advice: remove the package, treat the machine as compromised and renew keys, tokens and passwords from a clean device.
Analysis
Software supply chain attacks have been a constant theme this autumn. Just days ago we covered the LiteLLM supply chain attack with backdoors in PyPI and Docker packages. The Railway security incident also showed how important fast secret rotation is in developer environments. And the Brotli vulnerability in Node.js recently hit the runtime itself.
This case is technically simple but instructive. It shows that attackers deliberately pick names that sound like internal monorepos and micro-frontends. The defense lies less in malware scanners than in clean registry configuration.
Conclusion
The 14 packages from the “wiseke” account are a textbook example of npm dependency confusion: plausible names, inflated version numbers and a payload that quietly collects information without breaking the build. Whether there are real victims is unknown. Anyone using internal npm packages should still check today whether their scope is firmly bound to the private registry and whether CI servers can freely reach the internet. It takes little time and closes off a whole class of attacks.



