Red Hat npm 패키지가 털렸다: Miasma
TLDR Sec 보다가 등골 서늘해진 사건. 한 명의 GitHub 계정에서 시작된 32개 패키지, 96개 버전, 11만 다운로드의 도미노.
오늘 TLDR Sec 메일을 보다가 Bleeping Computer 기사 하나에서 손이 멈췄다.
“Red Hat npm packages compromised to steal developer credentials”
레드햇이다. 그 레드햇. 내가 RHCSA 따겠다고 그렇게 후벼팠던 그 회사.
근데 한편으론 별로 안 놀랐다. 요즘 npm 공급망 공격 뉴스가 거의 주간 연재 만화 수준으로 나오고 있어서… 이젠 “또 npm이야?” 가 자동반사로 나온다.
마침 OSCP 공부하면서 Post Exploitation, Credential Harvesting 이런 거 매일같이 보는 입장에서 — 이게 공격자 시점으로 보면 진짜 정석 of 정석이라 한 번 정리하고 가야겠다 싶었다.
1. 사건 요약: 무슨 일이 일어난 거냐
@redhat-cloud-services 네임스페이스 하위 패키지들이 털렸다.
숫자만 보자.
- 32개 패키지, 96개 버전 백도어 박힌 채로 npm에 publish됨
- 주간 다운로드 약 117,000회
- 발견 날짜: 2026-06-01
- 레드햇 공식: “내부 개발용 범위에 한정, 고객 영향 없음”
침투 경로가 클래식하다.
- 레드햇 직원의 GitHub 계정 하나가 털림
- 공격자가 그 계정으로 리포지토리에 악성 커밋을 push
- 거기에 GitHub Actions 워크플로우를 슬쩍 끼워넣음
- 그 워크플로우가 npm의 OIDC 토큰을 들고 publish 권한을 정상적으로 획득
- 백도어 박힌 버전이 npm 레지스트리에 합법적으로 올라감
여기까지 한 줄로 요약하면: “털린 GitHub 계정 1개 → 17만 명의 개발자 환경에 페이로드 자동 배달”.
OSCP에서 배우는 그 “Initial Foothold 하나만 잡으면 그 다음은 도미노다”라는 게 공급망에서 그대로 재현된 거다.
2. 페이로드 뜯어보기: Miasma
악성 payload는 index.js, 크기는 4.2MB. 자바스크립트 한 파일이 4MB대면 이미 그 자체로 수상하다. 정상적인 라이브러리 진입점이 그 크기가 될 일은 없다.
실행 방식은 더 클래식하다. package.json에 이 한 줄.
{
"scripts": {
"preinstall": "node index.js"
}
}
이거다. 이거 하나.
npm install 치는 순간 동의 없이 node index.js 가 돌아간다. 내 로컬이든, CI 러너든, 도커 빌드 안이든 — npm install이 도는 모든 환경에서.
npm의
preinstall/postinstall훅이 공급망 공격의 영원한 1군 페이로드 트리거인 이유다.
이 페이로드 이름은 Miasma. 보안 업계에서 추적 중인 신변종이고, 분류상으로는 Mini Shai-Hulud 계열로 분류된다. 4.2MB짜리 다단계 난독화 덩어리고, 까보면 안에서 또 까지는 러시아 인형 구조다.
3. 뭘 훔쳐가는데?
여기가 진짜 무서운 부분이다. 리스트만 보자.
- GitHub Actions secrets
- AWS / GCP / Azure credentials
- HashiCorp Vault tokens
- Kubernetes service account tokens
- npm / PyPI publishing tokens
- SSH keys
- Docker credentials
- GPG keys
.env파일 전체
개발자 PC에 있을 만한 거의 모든 종류의 인증 정보다.
내가 AWS에서 Azure로 인프라 옮길 때 잠깐 ~/.aws/credentials 에 키 박아놨던 거 생각하니 내가 노출됐으면 빼박으로 크레딧 다 털리고 천만원짜리 청구서가 날아왔을 수도 있겠다는 생각이 들었다.
저거 하나만 털려도 — 내 EC2 인스턴스 띄우고, 코인 채굴기 돌리고, S3 버킷 다 내려받고, 청구서로 나를 파산시킬 수 있다.
거기다 npm publish 토큰까지 같이 털리면? 이 사람이 관리하는 다른 패키지에도 백도어가 박힌다. 그게 다음 단계 전파다. 자기복제 웜이라는 게 이래서 무섭다.
4. 큰 그림: Shai-Hulud 계보
이게 단발성 사건이 아니라는 게 진짜 문제다. 시간순으로 정리해보자.
| 시기 | 이름 | 규모 | 특징 |
|---|---|---|---|
| 2025년 가을 | Shai-Hulud (오리지널) | 500+ 패키지 | npm MFA 피싱 → 토큰 탈취 → 자기복제 |
| 2025년 11월 | Shai-Hulud 2.0 | 25,000+ 악성 리포 | 약 350명 메인테이너 계정 침해 |
| 2026년 4월 | Mini Shai-Hulud | SAP 생태계부터 시작 | 변종, 더 가벼운 페이로드 |
| 2026년 5월 | Mini Shai-Hulud 확산 | @antv, TanStack 패키지 등 160+ | GitHub Actions 메모리에서 secret 직접 dump |
| 2026년 6월 | Miasma (오늘 글) | Red Hat 32패키지, 96버전 | OIDC publish 우회, 신변종 |
이름이 듄의 모래벌레다. 작명이 너무 잘 어울려서 화가 날 정도다. 한 마리가 들어오면 그 안에서 알을 까고, 까진 알들이 다시 다른 패키지로 기어들어간다.
lateral movement를 패키지 매니저 위에서 자동화한 거다. 이게 진짜 무서운 점.
5. 그래서 우리 같은 1인 개발자는 뭘 해야 하나
내가 막 거대 조직 보안팀이 아니니까, 현실적으로 할 수 있는 것만 추려봤다.
5-1. preinstall/postinstall 자체를 의심해라
npm에는 이런 옵션이 있다.
npm install --ignore-scripts
설치할 때 라이프사이클 스크립트(preinstall, postinstall 등)를 아예 무시한다.
물론 native module이 빌드 안 되는 경우가 생긴다. 그래도 로컬 dev 환경에선 기본값으로 켜놓고, 필요한 패키지만 예외 처리하는 게 훨씬 안전하다.
.npmrc 에 박아두면 된다.
ignore-scripts=true
이거 하나만 켜놨어도 Miasma는 내 노트북에서 못 도는 거다.
5-2. CI에서는 토큰 권한 최소화 + OIDC
GitHub Actions에서 npm publish할 때 장기 토큰을 secret에 박아두는 짓은 이제 진짜 그만해야 한다. OIDC trusted publishing 쓰면 단기 토큰만 발급된다.
근데 오늘 사건은 그 OIDC 통로조차 우회당한 케이스라… 마음이 복잡하다. 결국 GitHub 계정 자체의 보안(passkey, FIDO2, 의심스러운 워크플로우 추가에 대한 alert)이 최후의 방어선이라는 거다.
5-3. .env 와 자격 증명을 홈 디렉토리에 흩뿌리지 마라
이게 제일 부끄러운 부분인데, 솔직히 나도 했다.
~/.aws/credentials에 key 박아두기~/.npmrc에 publish 토큰 박아두기- 프로젝트 루트에
.env그대로 두기
저거 다 Miasma가 1순위로 긁어가는 경로다.
대안은 — AWS는 SSO 기반 단기 자격 증명, npm은 OIDC, 시크릿은 1Password CLI나 OS keychain 거쳐서 주입. 한 번 셋업해두면 그 다음부턴 편한데, 한 번 셋업하는 게 또 빡세다.
그리고… 로컬 환경에서 테스트 해야지.. 1인 개발자가 개발서버가 어디 있어요…
5-4. 사고 났다고 가정하고 살자
이게 OSCP 공부하면서 가장 크게 바뀐 마인드다.
안 털린다는 가정으로 시스템을 짜면 안 된다. 이미 털렸다는 가정으로 짜야 한다.
키는 정기 로테이션. .env 는 절대 커밋 안 함. AWS 계정엔 결제 알람 걸어둠. npm whoami 가 의도하지 않은 환경에서 안 뜨게 셸 분리. CI 환경의 권한은 production 데이터에 닿지 못하게 분리.
이거 다 해놓으면, 백도어가 한 번 흘러 들어와도 폭발 반경이 줄어든다.
마치며
내가 OSCP를 따겠다고 마음먹은 이유가 — “공격자 시점으로 시스템을 볼 줄 알아야 진짜 방어가 된다”였다.
오늘 사건이 그 명제의 살아있는 증거다.
공격자는 package.json의 preinstall 한 줄에 4.2MB짜리 페이로드를 묶어서, GitHub Actions가 OIDC로 합법적으로 publish하게 만들어버렸다. 어떤 단계에서도 “이상한 짓”이라고 단정짓기 애매한 합법적 흐름이다. 그래서 더 무섭다.
개발자가 평생 쳐대는 그 npm install 한 줄이 — 누군가에겐 리버스 쉘 한 줄이라는 거다.
나는 이제 새 프로젝트 시작할 때마다 가장 먼저 .npmrc 에 ignore-scripts=true 박아넣는 사람이 될 거다. 작은 거지만, 그게 OSCP 공부하면서 얻은 가장 실용적인 습관이 될 거 같다.
다음에 또 신변종 npm 웜이 나오면 — 그땐 어떤 새로운 우회 기법이 나올지 한번 지켜보자. 안 나올 리가 없다.
마침.
다른 글 보기
마케팅은 진짜 너무 깊은 물이고, 나는 수영을 못한다
유저 100명 찍고 본격 그로스 한답시고 DM 50통, 메일 수십통 돌린 어제의 기록. 결과는... 아무도 안 옴.
한 번 뜯어보는 github.dev 1-Click 토큰 탈취 익스플로잇
TLDR Dev에서 본 분석글. .ipynb 한 번 열기 = OAuth 토큰 통째 노출. WOW.
한 번 뜯어보는 mattpocock/skills
Caveman이 개웃겨서 설치해봤는데, 의외로 매우 쓸만함
좋은 PR이 뭔데?
매번 셀프 체크를 위한 PR만 올렸었다. 근데, 뭐 좋은 PR이라는게 있나?