A High Level Post Mortem of the eslint-scope Security Incident
Early today there was an incident regarding a module (eslint-scope
) that was hijacked on npm. The hijacked module attempted to steal tokens contained within .npmrc
to enable additional publishes . Here's a quick overview of everything that's happened, based on the information available so far.
*This post will be updated as more information becomes available. Feel free to ping me on Twitter with additional information, I’d be happy to make updates corrections as necessary. *
This has been totally from my point of view while observing and reaching out to individuals who I know it matters to. I figured I’d take a minute to summarize the entire event and give a quick post-mortem for y’all in case you don’t have as much time to investigate and work on this stuff as I do.
Module Highjacking
The hijacker of eslint-scope
published a new patch release of the module at 10:40 UTC. Normally, a new patch would automatically hit many of the individuals using the module (either directly or as a dependency of another module).
Today at 11:17 UTC, an issue was created in the GitHub repository of eslint-scope
regarding unexpected error messages which indicated that the downloaded module was malicious as of v3.7.2. The GitHub issue elicited rapid responses and quickly became ground-zero for the incident, as other users were able to reproduce and confirm the unexpected errors.
Passwords for npm accounts were not vulnerable to this attack.
The hijacked version of the module would load a file from pastebin and attempt to send users’ .npmrc
files back to the hijacker. Since .npmrc
contains authentication tokens for users' accounts, it’s reasonable to suspect that the hijacker’s code was intended to behave as a worm – gaining publish access to other accounts that don't have publish-time 2FA enabled on npm.
The origin of these new and unexpected errors was traced back to some moderately sloppy code, which some have suggested indicates the attacker didn’t have a firm understanding of certain aspects of basic best practices in both JavaScript and Node.js.
Another module, eslint-config-eslint
, was also infected but the attacker actually reverted it and went for the bigger fish – eslint-scope
, which has roughly 1000 times the weekly downloads. Both babel-eslint
and webpack
depend on the hijacked module eslint-scope
.
At this point, the ESLint team has published a post-mortem of their discoveries.
npm Team's Response
The npm team began investigating the issue early in the morning PT (16:13 UTC), which was a few hours after the initial incident began to garner attention.
In investigating, the npm team came to the conclusion that account credentials had been compromised and the malicious code was published by the compromised account, which had publish access to the module.
Not too long after, the npm team invalidated all tokens created prior to the publication of the hijacked module – which rendered any credentials received by the module’s hijacker useless. This action helped to ensure that additional modules would not be compromised by the same hijacker using valid credentials stolen in the initial attack. The npm team also began reaching out to notify affected individuals.
As a result of the token deletion, npm inadvertently took down the npmjs.com website for a short amount of time – it was brought back up within a relatively short time frame with zero additional issues.
At 18:52 UTC, the npm team confirmed on their Status Page that they had indeed invalidated all tokens and would be conducting further forensic analysis to understand how many modules and users were affected by the malicious code.
The npm team has also published a post-mortem in which they state that ~4500 accounts could have been affected by stolen tokens prior to the hijacked eslint-scope
module being unpublished, but as yet no evidence has been found that any of these accounts were affected prior to the full token purge.
The npm team did a good job handling the incident in a way that – while unfortunate – ensures that any stolen credentials are now effectively useless.
Current State of Things – the TL;DR
- The vulnerable module has been unpublished, and newer versions have been published over it to ensure that individuals don't try to install it.
- Tens of thousands of npm access tokens were deleted for the sake of security.
- npmjs.com went down temporarily
- ESLint has shared a post-mortem: https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes
- npm has shared a post-mortem: https://blog.npmjs.org/post/175824896885/incident-report-npm-inc-operations-incident-of
If you're still a bit uneasy, here are a few things you can do immediately to help ensure that you're not going to be affected further:
- Check internal registries to ensure that the
eslint-scope@3.7.2
andeslint-config-eslint@5.0.2
modules aren't cached - Make sure both
package-lock.json
andnpm-shrinkwrap.json
files don't includeeslint-scope@3.7.2
andeslint-config-eslint@5.0.2
- Run
npm cache clean
to ensure that your cache is flushed of the offending modules
If you’ve got an npm account and publish, it’s highly encouraged that you enable 2FA for your npm accounts. I personally have enabled it for both sign-in and publishing, and I suggest you do the same – especially if you maintain modules that others depend on