Cremit
/incidentsfield log
탐지캠페인유출지패턴LLM사고 사례방법론
↺rss↗cremit.io

incidents.cremit.io

실제 발생한 비인간 식별자(NHI) 크리덴셜 유출 사고를 정리한 인덱스. 운영: Cremit

둘러보기

  • 전체 사고
  • npm 공급망
  • CI/CD 침해
  • 방법론

구독

  • RSS 피드
  • @cremit_io
  • GitHub
// 상태
모니터 가동중
// 빌드
2026-05-20
// 출처
cremit · 서울, 대한민국
// 라이선스
CC BY 4.0

© 2026 Cremit. 출처 표시 시 자유롭게 재사용 가능.

홈/사고/eslint-scope-token-theft-2018
HIGH7.6·confirmed·공개 Jul 12, 2018·4분 분량

eslint-scope npm Publish Token Theft (2018)

An attacker stole an ESLint maintainer's npm credentials and published a malicious eslint-scope version that exfiltrated developer .npmrc tokens to a remote server.

Summary

On July 12, 2018, an attacker stole the npm publish credentials of an ESLint maintainer and published malicious versions of eslint-scope and eslint-config-eslint. The malicious code read the .npmrc file on the developer's machine, extracted the npm authentication token, and POSTed it to an attacker-controlled pastebin endpoint. The attack was a credential-harvesting worm: every developer who installed the package became a potential vector for further publish-token theft. ESLint detected the attack within hours and revoked the malicious versions, but not before an unknown number of authentication tokens were exfiltrated.

Timeline

  • 2018-07-12 ~02:49 UTC — Attacker logs into the compromised npm account and publishes eslint-scope@3.7.2 with malicious code.
  • 2018-07-12 ~03:24 UTC — Attacker also publishes eslint-config-eslint@5.0.2 carrying similar payload.
  • 2018-07-12 ~05:39 UTC — npm reports anomalous activity to ESLint; ESLint begins investigating.
  • 2018-07-12 ~07:00 UTC — Both malicious packages are unpublished. npm begins force-rotating credentials of any account that downloaded the affected versions.
  • 2018-07-13 — ESLint and npm publish post-mortems.

Attack Vector

The compromise was credential theft, not a maintainer handoff. The maintainer's npm credentials were obtained, almost certainly via password reuse — npm later confirmed the credentials matched a historical breach corpus. The attack chain:

  1. Attacker logs into a maintainer's npm account using stolen reused credentials.
  2. Attacker publishes new patch versions of widely-installed packages with credential-harvesting payload appended.
  3. Payload reads ~/.npmrc on the install target's machine, extracts the _authToken line.
  4. Payload POSTs the token to a pastebin endpoint controlled by the attacker.
  5. Attacker harvests pastebin contents, gains npm publish rights to whatever those tokens authorize.

The intended outcome was self-propagation. Each token harvested let the attacker publish malicious patch versions of further packages, harvesting more tokens, expanding the surface.

Tokens & Credentials Exposed

  • npm authentication tokens stored in ~/.npmrc on every machine that installed eslint-scope@3.7.2 or eslint-config-eslint@5.0.2 during the active window.
  • For developers who used the same machine for multiple npm scopes, the harvested token authorized publishing across all of them.
  • For organizations whose CI pipelines installed the malicious version into a runner that also held publish credentials, the runner's token was harvested.

The exposure window was ~5 hours, which sounds short but corresponds to billions of dependency-tree resolutions globally — every CI build kicked off in that window potentially pulled the malicious version.

Confirmed Impact

  • npm forced credential rotation for every account whose .npmrc was potentially exfiltrated. The exact number was not published.
  • No second-stage publishes were observed by the defender community before the malicious versions were unpublished. The window was short enough that the worm did not propagate visibly.
  • Long-tail risk persisted for any token harvested but not rotated. npm's forced rotation covered tokens used by accounts that downloaded the package, but tokens stored in long-lived CI environments may have been missed.

Mitigation & Lessons

The structural lessons:

  • Multi-factor authentication for publish rights is non-negotiable. npm rolled out 2FA enforcement for top-1000 packages in the months after this incident; mandatory 2FA for all public package maintainers landed years later.
  • Tokens in .npmrc are platform-scoped credentials. A token in ~/.npmrc is identity-equivalent to a logged-in npm session for that account. Treat it accordingly: avoid storing publish-scoped tokens on developer laptops at all.
  • Granular publish scopes matter. Fine-grained tokens that can publish only to a specific package or scope dramatically reduce blast radius if harvested. They were not available in 2018; they are now.
  • Provenance + 2FA + lockfile pinning is the defense-in-depth posture that would have stopped this attack at multiple layers today.

Cremit Analysis

This is the cleanest ghost-key case in the index. The credential involved had no human face — it was a long-lived static token in a config file, used routinely by automation. When the attacker presented it, npm had no way to distinguish "the real maintainer publishing a routine patch" from "an attacker holding a stolen token." Both look identical on the wire.

It is also a drifted-key case. The maintainer's npm credentials were almost certainly minted years before, used across multiple personal and work scopes, and reused as a password somewhere else along the way. By 2018 the credential reached more packages, with more downloads, than it did when first issued. Nobody had reviewed the scope.

The NHI Severity Index score of 7.6 reflects ecosystem-wide reach of eslint-scope (a common transitive dependency in JavaScript projects) tempered by the developer-environment reachability — the harvest target was developer laptops and CI runners, not production credentials directly. The blast radius is what made the attack worth attempting: a single harvested npm token could itself be used to ship the next malicious version, multiplying reach geometrically.

This incident set the precedent for the credential-harvesting npm worm pattern that would later show up in Shai-Hulud (2025–2026) at much larger scale. The technique did not change. What changed is the volume of credentials a modern developer or CI runner holds beyond just .npmrc.


참고 자료

  1. [1]
    Postmortem for Malicious Packages Published on July 12th, 2018
    primary·2018-07-13·eslint.org
  2. [2]
    npm Blog — Reported malicious module: getcookies
    primary·2018-07-13·blog.npmjs.org
  3. [3]
    Hacker breaches npm account, infects ESLint package
    reporting·2018-07-13·zdnet.com

관련 사고

2018-11-26·HIGH
event-stream / flatmap-stream Backdoor (2018)
2021-10-22·CRITICAL
ua-parser-js npm Account Compromise (2021)
2026-04-22·CRITICAL
Bitwarden CLI Supply Chain Compromise (2026)
최종 검토 / 2026-05-04검토자 / ben라이선스 / CC BY 4.0
// 사고 메타데이터
심각도
HIGH7.6
상태
confirmed
공개
2018-07-12
발생
2018-07-12 → 2018-07-12
벡터
npm supply chain
플랫폼
npm
토큰
npm Publish TokenEnvironment Variable
nhi severity index
점수7.6 / 10blast radiusecosystem-widereachabilitydeveloper-env권한variable
nhi kill chain
Ghost Key↗Drifted Key↗
지표
노출 기간1일