Mini Shai-Hulud 웜 — TanStack npm 공급망 공격 6단계 점검

본 가이드는 2026년 5월 11일 공개된 Mini Shai-Hulud 자기복제 웜이 TanStack/router 공식 이슈 #7383에 보고된 @tanstack/* npm 패키지 다수 손상 사건을 다룹니다. StepSecurity 위협 인텔 보고서에 따르면 이 웜은 정상 GitHub Actions 릴리즈 파이프라인을 탈취해 SLSA Build Level 3 증명까지 갖춘 악성 버전을 npm에 그대로 게시했습니다.

Mini Shai-Hulud 웜과 npm 공급망 공격 대응을 검토하는 개발자 워크스페이스 이미지
Photo by Steve A Johnson on Unsplash

분석 기준은 같은 보고서와 Socket 공급망 공격 정리 페이지의 IOC입니다. 본 글은 Node.js·Bun·GitHub Actions 기반 한국 백엔드·프론트엔드 팀이 즉시 수행할 점검표 관점으로 재구성했습니다.

1. 사건 개요 — 무엇이 다르고 왜 위험한가

StepSecurity 분석 기준 Mini Shai-Hulud는 2025년 원본 Shai-Hulud의 변종이며, 5월 11일 19시(UTC) 무렵 @tanstack/react-router·@tanstack/router-core 등 라우터·시작 관련 패키지에 악성 버전이 게시되었습니다. 동일 보고서는 TanStack 외 UiPath·DraftLab 등을 포함해 손상 PURL을 200개 이상 추적 중이며, @tanstack 네임스페이스에서만 84개 이상 손상이 확인되었다고 명시합니다.

핵심 위험은 패키지가 npm의 정상 OIDC 신뢰 게시자로 서명되었다는 점입니다. SLSA 증명은 “어떤 파이프라인이 산출했는가”만 보장할 뿐 파이프라인이 의도대로 동작했는지는 보장하지 않습니다. npm audit signatures만으로는 걸러낼 수 없습니다.

2. 침투 경로 — fork에서 npm 공식 게시까지

GitHub fork를 이용한 npm 공급망 공격 진행 단계를 형상화한 코드 저장소 이미지
Photo by Louis Tsai on Unsplash

2-1. fork에 페이로드 스테이징

같은 보고서에 따르면 2026년 3월 신규 GitHub 계정 voicproducoes가 5월 10일 TanStack/router를 fork한 뒤 단일 커밋 79ac49ee로 가짜 @tanstack/setup package.json과 약 2.3MB 단일 라인 난독화 JS를 추가했습니다. prepare 훅이 bun run tanstack_runner.js && exit 1을 실행해, 설치 시 페이로드가 백그라운드로 돌고 표면적으로는 optional 의존성 실패 로그만 남도록 설계되어 있습니다.

2-2. optionalDependencies로 정상 패키지에 주입

"optionalDependencies": {
  "@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c"
}

github:tanstack/router#<hash> 형식은 GitHub 공유 객체 스토리지 특성상 fork 커밋도 원 저장소 경로로 참조됩니다. StepSecurity 비교 기준 정상 타르볼 약 190KB가 손상 타르볼 약 905KB로 부풀었고, 압축 해제 크기는 같은 비교 기준 약 3.7배 증가했습니다. 패키지 사이즈 alert 룰만 있어도 이 단계에서 탐지가 가능합니다.

2-3. OIDC 토큰을 이용한 정상 워크플로 탈취

같은 보고서 분석에 따르면 정상 릴리즈 워크플로의 “Run Tests” 단계가 실패했음에도 같은 시간대에 패키지가 npm에 게시되었습니다. 페이로드가 id-token: write 권한과 ACTIONS_ID_TOKEN_REQUEST_TOKEN으로 정상 publish 스텝을 우회한 것으로 추정됩니다. npm publish 토큰만 회전해도 OIDC 신뢰 게시자 바인딩을 끊지 않으면 재발이 가능합니다.

3. 페이로드가 훔치는 자격 증명 범위

패키지 root의 router_init.js(StepSecurity 기준 SHA-256 ab4fcadaec49c0...)는 약 2.3MB 단일 라인 JS로, obfuscator.io 문자열 테이블·PBKDF2-SHA256 20만 회 반복 치환 암호·AES-256-GCM 페이로드의 3중 난독화를 거칩니다. 같은 보고서가 정리한 자격 증명 탈취 표면은 3가지입니다.

  • Runner.Worker 메모리: /proc/{pid}/mem을 sudo python3로 스캔해 워크플로 YAML이 참조하지 않은 시크릿까지 평문으로 추출, masking을 우회합니다.
  • 클라우드 메타데이터·Vault: AWS IMDSv2(169.254.169.254), ECS/Fargate(169.254.170.2), HashiCorp Vault(127.0.0.1:8200)에서 임시 자격 증명을 능동 탈취합니다.
  • 로컬 파일: 같은 보고서 기준 100개 이상의 경로에서 ~/.aws/credentials, ~/.ssh/id_rsa, ~/.npmrc, ~/.docker/config.json, ~/.claude.json, 암호화폐 지갑·메신저 쿠키·셸 히스토리를 수집합니다.

4. 페르시스턴스 — 재실행을 보장하는 방식

같은 보고서에 따르면 페이로드는 IDE와 OS에 다층 자동 실행 훅을 심어 둡니다.

  • Claude Code 훅: .claude/settings.jsonSessionStart가 매 세션 node .vscode/setup.mjs 호출.
  • VS Code 작업: .vscode/tasks.jsonrunOn: folderOpen으로 폴더 열 때마다 실행.
  • OS 데몬: macOS ~/Library/LaunchAgents/com.user.gh-token-monitor.plist와 Linux ~/.config/systemd/user/gh-token-monitor.service가 재부팅 후에도 GitHub 토큰을 감시·재유출.
  • 워크플로 주입: .github/workflows/codeql_analysis.yml 이름으로 toJSON(secrets)를 사용한 워크플로를 커밋. 커밋 작성자는 claude@users.noreply.github.com, 브랜치는 dependabot/github_actions/format/<dune-word>(fremen, sandworm, harkonnen 등) 패턴으로 위장합니다.

5. 한국 개발팀이 지금 점검할 6단계

npm 공급망 공격 대응을 위한 보안 점검 체크리스트 이미지
Photo by Markus Winkler on Unsplash

StepSecurity 보고서의 권고를 한국 팀 운영 환경에 맞춰 6단계로 재구성했습니다. 우선순위 순으로 진행을 권장합니다.

5-1. 락파일에서 손상 버전 확인

grep "@tanstack/" package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
grep -E "(draftlab|draftauth|uipath|tolka|taskflow-corp)" \
  package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null

찾아낸 버전을 StepSecurity 보고서 표와 대조합니다. 같은 보고서 기준 @tanstack/react-router의 손상 버전은 1.169.5·1.169.8이며, 직전 안전 버전(1.169.2)으로 핀 고정이 권장됩니다.

5-2. node_modules에서 IOC 파일 탐지

find node_modules -name "router_init.js" -type f 2>/dev/null
grep -r "@tanstack/setup" node_modules/*/package.json 2>/dev/null

같은 보고서 기준 정상 빌드 결과물에 router_init.js는 존재하지 않습니다. 한 건이라도 매칭되면 해당 호스트의 비밀이 유출되었다고 가정하고 대응합니다.

5-3. CI 로그·egress 감사

5월 11일 19시(UTC) 이후 실행된 Actions 런에서 @tanstack/setup 설치, filev2.getsession.org·api.masscan.cloud outbound, bun run tanstack_runner.js 흔적을 검색합니다. 보고서 IOC 도메인은 사내 egress 차단 룰에 즉시 반영하는 것이 안전합니다.

5-4. npm 토큰과 랜섬 메시지 확인

npm token list 결과에 IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner 설명이 붙은 토큰이 있다면 즉시 회수하지 말 것이 보고서 권고입니다. 회수 신호가 와이프 루틴의 트리거로 보고되므로, 호스트를 먼저 네트워크에서 격리하고 디스크 이미지를 떠 둔 뒤 토큰을 처리하십시오.

5-5. IDE·OS 페르시스턴스 제거

rm -f .claude/router_runtime.js .claude/setup.mjs .vscode/setup.mjs
git diff .claude/settings.json .vscode/tasks.json
launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist 2>/dev/null
rm -f ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
systemctl --user disable gh-token-monitor 2>/dev/null
rm -f ~/.config/systemd/user/gh-token-monitor.service

형상관리가 안 되는 사적 노트북은 위 명령만으로 부족할 수 있습니다. 보고서 권고에 따르면 침해 의심 머신은 자격 증명 회전 후 OS 재설치를 검토하는 편이 안전합니다.

5-6. 자격 증명 회전·지갑 자산 이동

노출 가능성이 있는 npm·GitHub·AWS·GCP·Kubernetes·Vault 토큰을 모두 회전합니다. 보고서가 명시한 대상에는 SSH 키, ~/.git-credentials, Slack·Discord 세션 쿠키, 암호화폐 지갑 파일이 포함됩니다. 지갑 파일이 있던 머신이라면 자산을 신규 지갑으로 즉시 이체하십시오.

6. 운영·아키텍처 가드 — cooldown·egress·OIDC 분리

적용 환경은 Node.js 22 LTS, npm 10 또는 pnpm 9, GitHub Actions 기반 CI를 가정합니다. 청소 이후 같은 사고가 재현되지 않도록 파이프라인 수준 가드를 추가합니다.

  1. 신규 버전 cooldown: 사내 사설 레지스트리(Artifactory·Verdaccio·Nexus) 앞단에서 time.modified 기준 N일 이내 버전을 차단. 보고서가 강조한 대표 방어이며, 7~14일 사이에서 시작하는 것이 현실적입니다.
  2. CI egress 화이트리스트: GitHub Actions는 Harden-Runner 등으로 알려지지 않은 호스트 통신을 즉시 차단. 보고서 IOC(filev2.getsession.org·api.masscan.cloud)는 기본 deny 대상으로 둡니다.
  3. OIDC 권한·신뢰 게시자 분리: 테스트 잡과 publish 잡의 토큰 권한을 분리, npm 신뢰 게시자에 별도 workflow path 지정, publish 잡을 별도 environment + manual approval 뒤에 둡니다.
  4. SLSA 다층 검증: “신규 게시 직후”·”패키지 사이즈 급증”·”IOC 파일명” 지표가 함께 있으면 자동 보류하는 다층 룰을 사내 정책에 추가합니다.

7. 정리 — 신뢰 체인이 한 단계 위로 올라갔다

Mini Shai-Hulud 사건의 메시지는 분명합니다. “공식 메인테이너의 정상 워크플로”는 더 이상 자동 신뢰의 마지막 기준이 아닙니다. TanStack/router 이슈 #7383의 시차 비교에 따르면 손상 게시와 커뮤니티 인지 사이는 수 시간 단위였고, 그 사이 한 번이라도 npm install이 돌면 CI 비밀과 로컬 자격 증명이 동시에 노출됩니다. 단기로는 5장의 6단계를, 중기로는 6장의 cooldown·egress·OIDC 분리를 백로그에 등록하기를 권장합니다.

8. 관련 글

이번 사건은 “오픈소스 신뢰 체인이 어디까지 무너질 수 있는가”라는 흐름의 한 장면입니다. 같은 흐름을 다른 각도에서 다룬 글을 함께 읽어 두면 사내 정책 설계에 도움이 됩니다.


📌 함께 보시면 좋은 글

※ 본 글은 AI(Claude)의 초안을 기반으로 편집자 검수를 거쳐 발행되었습니다. (한국 AI기본법 대응 고지)

이직·퇴사, 지금 움직여도 될지 헷갈리시나요?

막연히 불안한 건지, 정말 시점이 온 건지 판단이 어려울 때가 있습니다.

5분 체크리스트로 지금 상태를 먼저 정리해보세요.
결론을 대신 내리기보다, 스스로 판단할 기준을 잡는 데 도움을 드립니다.

무료 체크리스트 보기

아직 확신이 없다면, 지금이 ‘고민 단계’인지부터 먼저 점검해보세요