대상 독자: npm이나 pnpm으로 개발하거나, GitHub에 코드를 두거나, CI에서 배포하는 모든 사람. 보안 업체와 연구소의 공개 분석을 바탕으로 하며, 공격 절차나 샘플은 싣지 않습니다.
무슨 일이 있었나 (ChainDrop, 2026년 8월)
2026년 8월 4일
널리 쓰이는 캐시 관련 패키지를 관리하는 메인테이너의 GitHub 계정이 탈취되었습니다. 공격자는 프로젝트의 기존 GitHub Actions 릴리스 워크플로를 실행해 오염된 버전을 npm에 배포했습니다.4시간 이내
패키지 444개, 버전 2,212개가 오염되었습니다. 주간 다운로드 합계가 5억 회를 넘는 패키지도 포함되었습니다.설치 시
설치 시점의 훅이 npm, GitHub, 클라우드(AWS/GCP/Azure), SSH 키, Kubernetes, CI/CD 자격 증명을 수집했습니다. 공개된 분석에 따르면 CI 러너 메모리에서 긁어낸 단기 OIDC 토큰도 포함되었습니다.그 다음
훔친 자격 증명으로 피해자가 배포할 수 있는 모든 패키지를 다시 배포해 스스로 퍼졌고, 수집한 시크릿은 공격자가 만든 공개 GitHub 저장소로 유출되었습니다.
이 계열의 주된 피해: 비공개 저장소가 공개된다
Shai-Hulud 계열 웜은 훔친 GitHub 토큰으로 피해자의 비공개 저장소를 공개 저장소로 복사합니다. 이름이 -migration으로 끝나는 저장소가 보고되었습니다. GitHub가 뚫린 것은 아닙니다. 노트북이나 CI 러너에서 빼낸 토큰이 내 권한으로, 정상적인 작업으로서 이 일을 합니다. 그래서 "플랫폼이 고쳐 줄 때까지 기다린다"는 방어가 되지 않습니다.
왜 막지 못했나
의존성 추가 / CI에서 설치
↓ preinstall / postinstall이 자동 실행
내 PC나 러너에서 임의 코드 실행
↓ npm / GitHub / 클라우드 / SSH / CI 시크릿 수집
훔친 토큰으로 정상적인 작업 수행
비공개 저장소를 공개로 복사 / 패키지를 다시 배포해 확산
도움이 되지 않은 것
- 서명과 출처 증명 — 메인테이너 권한으로 정상 발급되었으므로 검증을 통과했다
- "유명한 대형 패키지니까" — 오염된 것이 바로 그런 패키지였다
- 버전 고정만 하기 — 새로 설치하거나 다음에 버전을 올릴 때 결국 받아 온다
- 플랫폼의 수정을 기다리기 — 사용된 것은 정상 토큰과 공개 API였다
도움이 되는 것
- 설치 스크립트를 기본으로 끄기 — 코드가 실행되지 않는다
- 새 버전 채택 전 대기 기간 — 공개부터 삭제까지의 기간을 피한다
- 수명이 짧고 범위가 좁은 토큰 — 훔친 토큰으로 할 수 있는 일과 기간을 줄인다
- CI 러너의 외부 통신 제한 — 유출 경로를 막는다
오늘 할 다섯 가지
내 lockfile을 검색한다
오염이 보고된 버전이 들어 있는지 확인합니다(예: keyv@6.0.0, flat-cache@6.1.24, file-entry-cache@11.1.6). 없으면 다행이지만, 2단계부터는 다음에 올 비슷한 공격에 대비하는 작업이므로 계속 진행하세요.
설치 스크립트를 기본으로 끈다
CI에서는 **npm ci --ignore-scripts**를 쓰고, pnpm은 .npmrc에 ignore-scripts=true를 설정한 뒤 정말로 빌드가 필요한 의존성만 명시적으로 허용합니다. 이번 공격이 의존하는 실행 단계를 없애므로, 가장 효과가 큰 단일 변경입니다.
새 버전은 며칠 기다렸다가 채택한다
릴리스가 나오자마자 받지 말고 3~7일 정도 기다리면 충분합니다. 이번처럼 공개부터 삭제까지가 몇 시간에서 며칠이라면, 기다리는 것만으로 피할 수 있습니다. 자동 업데이트 PR을 쓴다면 이 지연을 설정에 넣어 두세요.
2026-09-05 추가: 이제는 사람이 기억해서 지킬 필요가 없습니다. Node.js 공식 보안 가이드는 공급망 대책 중 하나로 --min-release-age(npm v11.10.0 이상)로 의존성 대기 기간을 설정해 최근 공개된 패키지의 설치를 피하는 방법을 들고 있습니다. 규칙 대신 설정으로 만들 수 있다면 설정으로 만드세요. 누군가 기억해야 하는 절차는 바쁜 날 건너뛰기 쉽습니다.
토큰을 점검하고 수명과 범위를 줄인다
GitHub 개인 액세스 토큰은 classic에서 fine-grained로 옮기고, 만료를 짧게 하고, 필요한 저장소로만 제한합니다. npm 배포 토큰을 CI에 그대로 두지 마세요. 키와 시크릿 다루는 법은 .env와 API 키의 무엇이 위험한가와 SSH 키의 최소 권한에서 다룹니다. 목표는 토큰을 도난당해도 피해가 작게 만드는 것입니다.
내 GitHub 계정을 점검한다
내가 만들지 않은 공개 저장소(이름이 -migration으로 끝나거나 설명이 낯선 것), 추가한 적 없는 GitHub Actions 워크플로, .vscode/tasks.json이나 .claude/에 들어간 실행 가능한 설정, 모르는 API 키나 SSH 키가 없는지 확인합니다. 의존성의 알려진 취약점을 기계적으로 감시하려면 osv-scanner 시작하기를 참고하세요.
감염이 의심되면 순서를 지켜라
연구자들이 강조하는 점이 하나 있습니다. 토큰을 폐기하기 전에, PC에 남은 상주 구성 요소(토큰 감시 스크립트 등)를 먼저 제거하라는 것입니다. 순서를 거꾸로 하면 상주 구성 요소가 폐기에 반응할 수 있습니다. 대략 다음 순서입니다.
1. 네트워크에서 분리한다
2. 지속성 장치와 의심스러운 파일을 제거한다
3. npm → GitHub → 클라우드 → SSH → Kubernetes 순서로 폐기하고 재발급한다
4. node_modules와 캐시를 지우고 깨끗하게 다시 설치한다
5. 공개 저장소와 패키지 배포 이력을 확인한다
로그가 없다면 답은 "깨끗하다"가 아니라 "알 수 없다"입니다. 침해되었다고 보고 진행하세요.
본 사이트의 견해: 서명은 출처를 보증할 뿐, 안전을 보증하지 않는다
서명과 출처 증명은 수년간 공급망 보안의 대표 권고였고, 이번 공격은 그것을 통과했습니다. 놀랄 일은 아닙니다. 서명은 누가 배포했는지를 알려 줄 뿐, 내용이 안전한지는 알려 주지 않습니다. 탈취된 계정의 정상 서명은 정상이면서 동시에 위험합니다. 그래서 본 사이트는 출처 증명을 안전하게 만들어 주는 통제가 아니라, 사고 후 영향 범위를 가리는 조사 도구로 봅니다. 예방은 다른 두 가지에 달려 있습니다. 설치 시점에 남의 코드를 실행하지 않는 것, 그리고 그 코드가 실행되는 곳에 시크릿을 두지 않는 것입니다.
출처
- Unit 42 (Palo Alto Networks) — ChainDrop: Inside a Self-Propagating npm Worm (확산 방식, 수집된 자격 증명, 침해 지표)
- StepSecurity — ChainDrop npm Worm (탐지 지표와 복구 순서)
- Elastic Security Labs — CHAINDROP worm hits 400+ npm packages
- Node.js, "Security Best Practices" — nodejs.org (공급망 공격 경로와 대책:
--ignore-scripts, lockfile,npm ci,--min-release-age대기 기간. 2026년 9월 5일 확인) - SecurityWeek — Over 400 NPM Packages Infected in ChainDrop Supply Chain Attack (규모와 경과)
- Wiz — Shai-Hulud npm Supply Chain Attack (비공개 저장소를 공개로 복사하는 수법)
다음으로 읽기
- 2026년 사례: TanStack, Nx Console, GitHub로 이어진 연쇄 — 개발자가 확인할 것
- 실천: osv-scanner로 의존성 CVE를 기계적으로 감시하기 / gitleaks로 커밋 시점에 시크릿 막기
- 기초: .env와 API 키의 무엇이 위험한가 / SSH 키의 최소 권한
- 비교: 자체 호스팅 Git과 GitHub, 어느 쪽이 안전한가
- 의존성을 통해 들어오는 결함: Node.js의 프로토타입 오염 (병합 코드를 의존성이 썼더라도 해당된다)
- 용어: 멀웨어란
- 같은 유형: 2026년 침해는 정상 자격 증명으로 들어왔다 (훔친 토큰이 평범한 작업을 수행하는 같은 형태)
FAQ
Qnpm install만 했는데 어떻게 자격 증명이 털리나요?
패키지에는 설치할 때 자동으로 실행되는 스크립트(preinstall / postinstall)가 들어 있을 수 있기 때문입니다. 즉 의존성을 추가하는 것은 그 코드를 내 권한으로 실행하도록 허락하는 것과 같습니다. ChainDrop은 바로 이 방법으로 npm, GitHub, 클라우드, SSH, CI/CD 자격 증명을 수집했습니다.
Q비공개 저장소가 공개된다는 것은 무슨 뜻인가요?
이 계열의 웜은 훔친 GitHub 토큰으로 피해자의 비공개 저장소를 공개 저장소로 복사합니다. 이름이 -migration으로 끝나는 저장소가 보고되었습니다. GitHub 자체가 뚫린 것은 아닙니다. 내 PC나 CI에서 빼낸 토큰이 내 권한으로 그 작업을 수행한 것입니다. 그래서 플랫폼 쪽 수정을 기다려서는 막을 수 없습니다.
Q서명과 출처 증명이 있는 패키지는 안전하지 않나요?
이번에 뚫린 것이 바로 그 부분입니다. 공격자는 메인테이너 권한으로 프로젝트의 기존 릴리스 워크플로를 실행했기 때문에, 오염된 버전에도 정상적인 출처 증명이 붙었습니다. 서명은 누가 배포했는지를 보증할 뿐, 내용이 안전한지는 보증하지 않습니다. 탈취된 계정의 정상 서명도 정상 서명입니다.
Q오늘 당장 가장 효과적인 한 가지는 무엇인가요?
두 가지입니다. 설치 스크립트를 기본으로 끄고(npm ci --ignore-scripts, pnpm은 ignore-scripts=true), 갓 나온 버전을 바로 채택하지 말고 며칠 기다리는 것입니다. 앞의 것은 코드가 아예 실행되지 않게 하고, 뒤의 것은 가장 위험한 기간, 즉 공개부터 삭제까지의 몇 시간에서 며칠을 피하게 해 줍니다.