CVE-2025-54313: Prettier Config Package Hijacked
Today I was doing the rounds of security analysis on our repositories (a routine I perform once a month), and I came across a new CVE that truly shook me. I immediately removed the affected package from all our active repos, no matter which platforms our projects run on. That CVE is CVE-2025-54313, a high-severity supply chain attack involving the popular eslint-config-prettier npm package. This widely used linting configuration (over 30 million weekly downloads) was compromised after its maintainer fell victim to a phishing attack. The attacker published malicious versions of eslint-config-prettier (and some related packages) containing code that infects Windows machines with malware. In this post, I'll provide both a high-level overview and a technical deep dive into what happened, along with a timeline of events, indicators of compromise, affected versions, and steps you should take to remediate and protect your projects.
What Happened and Why It Matters¶
On July 18, 2025, the maintainers of eslint-config-prettier discovered that several new versions of the package had been published to npm without any corresponding commits or code changes on GitHub. This immediately raised red flags in the open-source community, as legitimate releases are almost always tied to real code changes. A community member (Dasa Paddock) opened an issue on the project's GitHub repository to report the suspicious activity, and others quickly chimed in. Shortly thereafter, the package’s maintainer (GitHub user JounQin) confirmed that he had unknowingly fallen prey to a phishing email, which allowed an attacker to steal his npm credentials and publish the compromised versions. The phishing email was cleverly spoofed to look like an official message from npm: it came from "[email protected]," but the login link actually pointed to a malicious lookalike domain npnjs[.]com. JounQin immediately revoked the leaked npm token, apologized for the incident, and began working on new clean releases to replace the bad versions.
Phishing email that tricked the maintainer of eslint-config-prettier. The email was crafted to appear as a legitimate npm support message, even using a spoofed "[email protected]" sender address, but the embedded link led to a fake npm login page at the domain npnjs[.]com
. Entering credentials there gave attackers access to the maintainer’s account.
The CVE-2025-54313 vulnerability is essentially a supply chain compromise. By stealing the maintainer’s credentials, the attackers gained the ability to publish malicious package versions under the trusted name of a highly popular project. ESLint-config-prettier alone is a dev dependency integrated into countless JavaScript projects to coordinate ESLint and Prettier rules, so a compromise to this package had potential to impact many developers. The malicious versions introduced in this attack included a payload that executes only on Windows systems, granting remote code execution (RCE) capabilities to the attacker. Fortunately, most production servers and CI environments run Linux, and eslint-config-prettier is typically used as a development-time tool (not shipped with production application code). This means the blast radius was somewhat limited, it primarily threatened developer workstations or any CI pipelines running on Windows, rather than end-user deployments. However, for any developer or organization using Windows, the impact was serious: the malware could run with the privileges of the user or CI agent, potentially installing further malware, stealing sensitive data, or pivoting to other systems. In short, this incident matters because it demonstrates how a single maintainer’s account compromise can cascade into a widespread threat, even if the immediate damage was constrained by platform in this case.
Timeline of the Compromise¶
To understand how this incident unfolded, here is a timeline of key events in the eslint-config-prettier compromise and its aftermath:
- July 18, 2025: Four new versions of
eslint-config-prettier
(8.10.1, 9.1.1, 10.1.6, 10.1.7) were published on npm. Developers quickly noticed that these versions had no corresponding commits or code changes on GitHub, which was highly suspicious. About an hour after the malicious release, a GitHub issue was raised reporting the anomaly, prompting investigation by the community and maintainers. - July 18, 2025 (later that day): Maintainer JounQin confirmed that he was phished via email. The attackers sent a convincing fake npm login request (using the domain
npnjs.com
) which led him to enter his credentials and inadvertently hand over an npm auth token. With this token, the attackers had published unauthorized, malware-laced versions of eslint-config-prettier and several other packages he maintains. Upon discovering the breach, JounQin revoked the compromised token, deprecated the malicious package versions on npm, and published new clean versions to replace them (eslint-config-prettier v8.10.2, v9.1.2, v10.1.8, etc.). He also apologized to users and took responsibility for the oversight in security. - July 19, 2025: The issue was escalated and an official CVE identifier CVE-2025-54313 was assigned to this supply chain attack. Security analysts began publishing details. For example, the National Vulnerability Database entry described how “installing an affected package executes an install.js file that launches the node-gyp.dll malware on Windows.”. By this time, automated tools and scanners also started flagging these package versions, given the CVE’s CVSS score of 7.5 (High severity).
- July 19–21, 2025 (Related attacks): It became apparent that this was part of a broader npm phishing campaign. On July 19, another popular npm package named “is” (with millions of downloads) was found to have been similarly compromised after its maintainer fell for what appears to be the same phishing scheme. Soon after, on July 21, the package “got-fetch” (about 50k weekly downloads) was also hijacked via the same method. In the got-fetch incident, the attacker used a different malware payload (an infostealer dubbed “Pycoon” delivered via a
crashreporter.dll
). These related events confirmed that a single threat actor (or group) was systematically targeting high-value npm maintainers using credential phishing and then publishing malware through their packages. The maintainer of got-fetch responded by deprecating the package entirely and advising users to switch to Node’s built-in fetch API. While these are separate packages, it's important to be aware of them, as they stem from the same campaign exploiting the trust in npm package maintainers. - July 23, 2025: Security firms provided deeper analysis of the malware involved. For instance, CrowdStrike researchers reported on their detections and revealed that the malicious DLL in eslint-config-prettier (which they dubbed “Scavenger”) was part of a two-stage attack designed to steal credentials and sensitive data from infected systems. By this date, most major security tools and package managers had updated their advisories, and developers worldwide were auditing their projects to eradicate the compromised versions.
Throughout this timeline, communication was rapid and transparent. The community-driven alert on GitHub and Twitter (X), quick action by the maintainer to deprecate packages, and timely updates by security teams helped limit the spread of the malware. Within a day or two, most of the damage was contained, but the incident serves as a stark reminder of the risks in software supply chains.
Technical Deep Dive: How the Attack Worked¶
At the heart of CVE-2025-54313 is a malicious post-installation script bundled into the compromised package versions. NPM packages can include lifecycle scripts that run automatically when the package is installed. In this case, the attackers added an install.js
script to eslint-config-prettier (and the related packages) that executes as soon as the package is added to a project.
Inside the install.js
was a function deceptively named logDiskSpace()
. Despite its benign name, this function had nothing to do with disk space. Instead, it checked if the code was running on a Windows platform and, if so, proceeded to execute a hidden malicious DLL file included in the package (named node-gyp.dll
) by invoking the Windows rundll32.exe
utility. In simpler terms, installing the package on Windows would immediately launch the DLL as a payload. On non-Windows systems (Linux or macOS), the script detects the OS and exits, doing nothing. This design choice meant the malware specifically targeted Windows environments, which often include many developer laptops or build agents in organizations that use Windows.
So, what does the node-gyp.dll
payload do? Analysis by security researchers revealed that this DLL is a trojan malware (named “Scavenger” by CrowdStrike) built to steal sensitive information from the infected system. When loaded via rundll32
, the DLL runs with the same privileges as the user who initiated the install. According to CrowdStrike’s deep dive, the DLL first reads the user’s npm configuration file (%USERPROFILE%\.npmrc
on Windows) and exfiltrates any tokens or credentials found there. (Many developers have auth tokens in their npmrc for accessing private registries or publishing packages, so this is a juicy target for attackers to potentially compromise more packages or accounts.) Next, the DLL drops a second-stage malware payload to disk – an infostealer focused on the user’s web browser data. This second-stage trojan would seek out things like saved session cookies, browsing history, or cached credentials, aiming to gather additional access to the victim’s online accounts or corporate systems.
In summary, the malicious packages functioned as a dropper: upon installation on a Windows machine, they would immediately run a DLL that acts as a first-stage loader, which then deploys a second-stage malware. The ultimate goal appears to be credential theft and potentially deeper infiltration. The specific malware (Scavenger) had a multi-pronged approach: steal npm credentials (to possibly facilitate further supply-chain attacks or abuse in npm), and steal browser data (which could include authentication tokens to other services, corporate intranets, etc.). Notably, early VirusTotal scans showed that only a minority of antivirus engines detected the node-gyp.dll
file as malicious (19 out of 72 engines at the time), meaning many endpoint protections might have initially missed this attack.
Impact and Severity¶
CVE-2025-54313 is rated High severity (CVSS 7.5) because it enables a form of remote code execution and can compromise the integrity of systems. However, it's important to understand the scope of impact in practical terms:
- Affected Environment: The malicious code only executes its payload on Windows platforms. If you installed an affected version on a Linux or macOS system, the
install.js
script would detect the OS and abort. This significantly limits the reach of the malware in typical server or containerized environments, since most CI/CD pipelines and production deployments use Linux-based containers or VMs by default. In fact, eslint-config-prettier is almost always used as a development dependency (for code linting and formatting) and is not included in production runtime bundles. So, an average end-user application in production was unlikely to be directly running this malicious code. - Who Is at Risk: The primary risk was to developers and CI pipelines running on Windows. For example, if a developer on a Windows PC did a fresh install of project dependencies (e.g.,
npm install
) and inadvertently pulled in one of the compromised versions, their machine could be infected. Similarly, if any organization had a Windows-based build agent that installed these dependencies, that agent could be compromised. Once the malware runs, it could potentially access any files and network resources that the user or build agent account has access to, which might include source code, credentials, and internal network services. - Potential Damage: The payload was designed to steal credentials and sensitive data (npm tokens, browser data). tolen npm tokens from developers could be extremely dangerous – attackers could use them to publish new malicious releases of other packages (if those tokens have publish rights), or access private code. Stolen browser data could lead to session hijacking of other accounts the developer is logged into (for example, if the developer had an active session to a cloud provider or version control system, the malware might extract that). Additionally, since the malware could run arbitrary code via the DLL, it’s possible it could install further backdoors or persist on the system.
- Severity Justification: While not a worm or ransomware that directly hits production servers, this attack is still high severity because it compromises the software supply chain and developer infrastructure. The integrity impact is high – malicious code executed in your development environment can taint build artifacts or be an entry point for deeper breaches (for instance, by exfiltrating secrets used during builds). The attack complexity was relatively low (phishing a maintainer) and required no privileges or user interaction beyond the normal act of installing a package, which many developers do routinely. Snyk’s security team even rated this issue as Critical (CVSS 9.2) on their scale, reflecting the serious implications if it had gone unnoticed. Thankfully, quick detection and the Windows-only trigger limited the real-world fallout.
In essence, the impact was largely on the development lifecycle rather than direct end-user exploitation. It's a wake-up call that even dev tools we take for granted can become attack vectors. Each compromised developer machine or CI pipeline could serve as a stepping stone for attackers to move laterally into more sensitive systems (for example, by stealing cloud credentials or inserting malicious code into software builds). The high severity rating acknowledges that, under slightly different circumstances (e.g., if the payload ran on Linux too, or if this was a library shipped in production), this could have been catastrophic. Even as it stands, any Windows-centric development shop had to treat this as a serious breach incident.
Affected Packages and Versions¶
Several packages maintained by JounQin were compromised in this attack. If your project has any of the following, you should check which version you’re using immediately:
- eslint-config-prettier: 8.10.1, 9.1.1, 10.1.6, 10.1.7 (💡 These are the malicious versions. Safe patched versions are 8.10.2, 9.1.2, 10.1.8 and above.*)
- eslint-plugin-prettier: 4.2.2, 4.2.3 (Malicious versions; update to 4.2.4 or later.)
- synckit: 0.11.9 (Malicious version; update to 0.12.0 or later.)
- @pkgr/core: 0.2.8 (Malicious version; update to 0.2.9 or later.)
- napi-postinstall: 0.3.1 (Malicious version; update to 0.3.2 or later.)
All the above packages were published by the same compromised maintainer account on July 18, 2025. The npm Registry team has marked these versions as deprecated, meaning if you attempt to install them now, you should get a warning. The maintainer has released fixed versions (noted above) that are free of the malicious code. If you are using any variant of these packages, ensure you are not on one of the listed bad versions. It’s worth noting that the malicious versions have been removed or flagged, so new installations should grab the safe versions by default but this only helps if your version range allows it. If you explicitly pinned a version (or your lockfile is still pointing to a cached malicious tarball), you could still be at risk. Always double-check.
(Note: Two other packages, is and got-fetch, were also compromised in the same time frame via similar attacks on their maintainers. Those packages are not maintained by JounQin and are technically separate incidents, so they are not covered by CVE-2025-54313. However, they were part of the broader campaign. If you use [email protected]
or [email protected]
, or [email protected]
or 5.1.12
, treat those as compromised as well and upgrade immediately.)
Indicators of Compromise (IoCs)¶
If you suspect that one of your systems or projects may have pulled in an infected version of eslint-config-prettier (or its related packages) on a Windows machine, here are some indicators of compromise and things to check:
- Presence of the malicious DLL: Look for a file named
node-gyp.dll
in your project’snode_modules
directory (specifically under the folders of the above packages) or elsewhere on the system. This file is not part of any normal eslint-config-prettier release. Its presence strongly indicates the malicious package was installed. The SHA-256 hash of the malicious DLL’s first-stage loader is32d0dbdfef0e5520ba96a2673244267e204b94a49716ea13bf635fa9af6f66bf
, and the second-stage stealer’s hash is5bed39728e404838ecd679df65048abcb443f8c7a9484702a2ded60104b8c4a9
, though simply finding the file via name is a good first step. If your antivirus or endpoint protection quarantined a file with that name, that’s a sign as well. - Unusual
rundll32.exe
process execution: The attack works by spawning arundll32.exe
process to load the DLL. If you have logging on your machine or an EDR (Endpoint Detection & Response) tool, check for any instances ofrundll32.exe
being executed with a command line referencingnode-gyp.dll
. This would be a clear indicator that the malicious script ran. CrowdStrike noted that their detections flaggedrundll32.exe
spawning from the Node process as suspicious in this case. - Communication to malicious domains: The Scavenger malware was observed contacting certain command-and-control (C2) domains to exfiltrate data. Notably, domains like
firebase[.]su
,dieorsuffer[.]com
, andsmartscreen-api[.]com
were associated with this malware’s network traffic. If you have network logs or DNS logs, any traffic from a developer machine or build server to those domains (especially around the timeframe of July 18–19, 2025) is a strong sign of compromise. Similarly, the phishing domainnpnjs.com
is an IoC; any emails or web requests involvingnpnjs.com
are malicious by nature. - Suspicious changes in npm account or tokens: Since the malware targets
.npmrc
, one fallout could be that your npm credentials were stolen. Keep an eye on your npm account for any unauthorized tokens or package publications. If you see a new npm token that you didn’t create or, worse, malicious packages published under your name, it’s a red alert that your credentials were likely compromised. In this incident, JounQin noticed a new token was added to his account without his knowledge (which was the stolen one). - Unusual files or processes on system: The second-stage payload (infostealer) might drop additional files or have a persistent process. While specific details of that payload (often malware like an info-stealer trojan) can vary, any new or unexpected executables running on the developer machine soon after the install could be an indicator. Running a reputable antivirus or anti-malware scan may pick up known signatures (by now, the trojan node-gyp.dll has been identified by multiple AV engines). Check your system for any newly installed programs or scheduled tasks that you don't recognize.
If you determine that a machine was likely compromised (e.g., you found the DLL or evidence it executed), you should treat it as a security incident. This may involve taking the machine offline, doing a forensic analysis, and wiping or rebuilding it if necessary to ensure the malware is completely removed. Also, assume that any credentials used on that machine might be stolen – not just npm, but potentially browser logins, SSH keys, etc., depending on what the second-stage collected. That leads to the next crucial section: remediation.
Remediation Steps¶
If your projects or systems were affected (or you want to proactively ensure they won’t be), take the following steps immediately:
- Upgrade or remove the compromised packages: Ensure you are not using any of the tainted versions listed above. Upgrade
eslint-config-prettier
to a safe version (8.10.2, 9.1.2, 10.1.8 or newer) and similarly update the other packages to their patched versions or remove them entirely. If possible, perform a clean reinstall of dependencies after upgrading (to flush out any cached malicious artifact). Consider pinning your dependencies to known-good versions in your package.json or lockfile so that you don’t inadvertently grab a compromised version in the future. - Audit your dependency lockfiles: Check your
package-lock.json
,yarn.lock
,pnpm-lock.yaml
, or other lockfiles for any references to the bad versions. If you find them, update the lockfile by reinstalling dependencies after removing or banning those versions. This ensures no developer or CI build will accidentally install the malware version due to a lockfile entry. Many package managers have audit or deduplication tools that can help identify and resolve any lingering references. - Inspect CI/CD logs and systems (especially Windows runners): If you ran any builds, tests, or deployment pipelines between July 18, 2025 and the time you upgraded, review those logs carefully for anomalies. Look for any mention of
install.js
scripts running or errors/exits that are unusual. Pay attention to Windows build agents – if, for example, your project’s GitHub Actions or Jenkins runners include a Windows job that could have installed these packages, scrutinize those. Check for any irregular behavior on those machines around that time (high CPU usage, strange log messages, etc.). If any of those machines were compromised, they should be pulled from service and cleaned/rebuilt. - Rotate secrets and credentials: As a precaution, rotate any secrets that might have been accessible in the environment where the compromised package ran. This includes npm tokens (revoke and recreate them), API keys, database passwords, or any credentials that were stored in plaintext or in environment variables during your builds. Also consider invalidating user sessions if your browser data may have been taken – for instance, sign out of web services and log back in to invalidate stolen cookies. The potential theft of .npmrc tokens means attackers could impersonate you on npm, so that’s a top priority to change.
- Run malware scans on developer machines: If a developer executed the malicious install, run a thorough antivirus/malware scan on that developer’s machine. The initial DLL might have been removed after running (or not), but the second-stage infostealer could still be present. Make sure the machine is clean. In some cases, a full OS reimage might be the safest route if you want to be sure all traces are gone.
- Review other packages by the same maintainer: In this specific case, JounQin’s packages were the ones compromised. He has already checked and updated those he identified (listed above). But a good practice in any such incident is to review any other packages from the affected maintainer. A GitHub user in the issue discussion cautioned that all packages by this maintainer should be scrutinized for tampering. It appears only the ones listed were affected, but it’s wise to stay vigilant.
- Stay informed on security feeds: This incident evolved quickly, with updates (like the expansion to is and got-fetch packages) coming within days. Subscribe to security alerts for the dependencies you use (services like GitHub Dependabot alerts, Snyk, etc., or follow reliable security blogs) so you get timely notifications of such compromises. Early awareness and quick action are key to minimizing damage.
Following the above steps will help ensure that your projects are clean from this specific threat. Going forward, consider implementing additional safeguards such as enabling 2FA on your npm accounts, using read-only tokens for CI where possible (to limit what an attacker can do if a token is stolen), and even using tools that can restrict or vet post-install scripts. For example, some companies use allow-lists or block-lists for install scripts in Node packages as a policy, since relatively few packages truly need them.
Conclusion and Key Takeaways¶
The eslint-config-prettier compromise (CVE-2025-54313) underscores a broader lesson: our software supply chain is only as secure as the humans who maintain it. In this case, a talented open-source maintainer was tricked by a phishing email, which is a reminder that even savvy developers can be vulnerable to targeted social engineering. One moment of negligence led to malicious code potentially reaching millions of users downstream. The incident was mitigated swiftly, but we might not always be so lucky.
Key takeaways from this event include:
- Maintain vigilance as both users and maintainers: If you maintain packages, enable two-factor authentication on your accounts and consider using hardware security keys to prevent token theft. Be skeptical of emails asking for credential verification, npm will never ask you to log in via an email link to verify your account. As a user, keep an eye on the release activity of your dependencies; an unexplained version jump with no code changes is a red flag worth investigating.
- Implement defense in depth: Relying on the upstream ecosystem’s security is not enough. Use tools that scan for malicious or vulnerable packages in your dependency tree. Employ runtime or install-time security tools (for example, package firewalls or lockfile auditing) that can catch unusual behavior. In this case, some organizations’ security software did catch the
rundll32
call as malicious. If your endpoint protection flags something during a package install, don’t ignore it as a false positive without investigation. - Least privilege and isolation: Developers often have broad access on their machines (source code, credentials, etc.). Consider running build processes in isolated containers or VMs, especially for untrusted code from the internet. And use least-privilege principles for CI: if an agent doesn’t need internet access or certain secrets to do its job, don’t provide them. This can limit what a malicious package can steal or affect.
The eslint-config-prettier compromise turned out to be less damaging than it could have been, primarily because of the Windows-only payload and quick community response. However, it’s a powerful case study in supply chain security. The next attack might not have those limiting factors. As developers, we must be prepared: keep dependencies up to date, respond rapidly to security alerts, and foster a culture of security awareness. After all, the trust we place in open-source maintainers is enormous – and as this incident shows, that trust can be abused through no fault of the maintainer if attackers find a way in. Strengthening account security (with measures like MFA, scoped access tokens, and better vigilance against phishing) is essential.
In the end, what “shook” me about CVE-2025-54313 was how quickly a ubiquitous tool could turn into a potential backdoor. By promptly removing or updating the compromised package across all our projects (yes, even in those not running on Windows, out of an abundance of caution), we mitigated the risk. I hope sharing this detailed analysis helps you do the same and perhaps encourages some preventative measures for the future. Stay safe out there, and happy (secure) coding!
FAQs
What is CVE-2025-54313 and why is it serious?
CVE-2025-54313 is a high-severity supply chain attack where a compromised npm maintainer account was used to publish malicious versions of eslint-config-prettier
, a widely used dev dependency. The attack targeted Windows systems and executed malware on install.
Which versions of eslint-config-prettier were affected?
Malicious versions include 8.10.1
, 9.1.1
, 10.1.6
, and 10.1.7
. Safe versions are 8.10.2
, 9.1.2
, 10.1.8
and later.
What platforms are affected by the malware?
Only Windows systems are impacted. The malware used a postinstall script that conditionally executed a DLL payload via rundll32.exe
on Windows.
How can I check if my system or project is compromised?
Audit your package-lock.json
or node_modules
for affected versions. Look for suspicious files like node-gyp.dll
, unusual rundll32.exe
executions, or network calls to known C2 domains.
What should I do if I used an affected version?
Immediately upgrade to safe versions, revoke compromised npm tokens, rotate any exposed secrets, and run a malware scan, especially if the install occurred on Windows.