TanStack npm 패키지, ‘미니 샤이-훌루드’ 공격에 뚫렸다
2026년 5월 11일, 전 세계 개발 커뮤니티를 충격에 빠뜨린 사건이 발생했습니다.
popular한 JavaScript 라이브러리 모음인 @tanstack 네임스페이스 하의 42개 npm 패키지에 악성 코드가 삽입되어, 84개의 악성 버전이 불과 6분이라는 짧은 시간 동안 배포되었습니다.
더욱 심각한 점은 이번 공격이 계정 탈취가 아닌, 합법적인 개발 파이프라인을 장악하여 이루어졌다는 사실입니다.
이는 소프트웨어 공급망 공격의 새로운 지평을 열었으며, 개발자들의 보안 의식을 다시 한번 재고하게 만드는 계기가 되었습니다.
공격의 전말: ‘미니 샤이-훌루드’의 진화
이번 공격은 ‘팀 PCP(TeamPCP)’라는 이름으로 알려진 위협 그룹에 의해 자행된 것으로 추정됩니다.
이들은 ‘샤이-훌루드(Shai-Hulud)’라는 웜(worm) 기반의 공격 도구 체인을 활용해 왔으며, 이번에는 ‘미니 샤이-훌루드(Mini Shai-Hulud)’라는 이름으로 더욱 정교화된 공격을 감행했습니다.
이 공격은 단순히 패키지에 악성 코드를 삽입하는 것을 넘어, SLSA(Supply-chain Levels for Software Artifacts)의 ‘빌드 레벨 3(Build Level 3)’ 수준의 유효한 증명서(provenance attestation)를 생성했다는 점에서 전례 없는 파장을 일으켰습니다.
SLSA는 소프트웨어 빌드 과정의 투명성과 신뢰성을 높이기 위해 고안된 프레임워크로, 악성 패키지가 합법적인 빌드 과정을 거친 것처럼 보이게 함으로써 탐지를 어렵게 만들었습니다.
이는 소프트웨어 공급망 보안의 근본적인 취약점을 드러내는 사건으로 평가됩니다.
상세 비교 분석: 이전 공격과의 차이점
샤이-훌루드 공격은 이번이 처음이 아닙니다.
과거에도 여러 차례에 걸쳐 npm 생태계를 위협해 왔으며, 각 파동마다 더욱 발전된 공격 기법을 선보였습니다.
특히 이번 ‘미니 샤이-훌루드’의 핵심은 SLSA 증명서를 악용한 것입니다.
이전 공격들과 비교하여 어떤 점에서 차이가 있는지 살펴보겠습니다.
| 공격 웨이브 | 시점 | 규모 | 핵심 진화 내용 |
|---|---|---|---|
| 1세대 샤이-훌루드 | 2025년 9월 | 500+ 패키지, 700+ 저장소 | 최초의 자가 복제 npm 웜, TruffleHog를 이용한 비밀번호 탈취 시도 |
| 샤이-훌루드 2.0 | 2025년 11월 | 492 패키지, 1.32억 월간 다운로드 | preinstall 훅 사용으로 인간 상호작용 없이 자동 실행, 홈 디렉토리 파괴 기능 추가 |
| 미니 샤이-훌루드 (1차) | 2026년 4월 | SAP/Intercom 생태계 대상 | AI 코딩 에이전트 지속성 확보 시도, 암호화된 데이터 유출, 러시아어 로케일 예외 처리 |
| 미니 샤이-훌루드 (2차) | 2026년 5월 | 373개 악성 버전, 169개 패키지 | 최초로 유효한 SLSA 빌드 레벨 3 증명서 포함, P2P C2 통신 방식 사용 |
이전 공격들이 주로 자체 복제 능력이나 자동 실행에 초점을 맞췄다면, 이번 공격은 보안 검증 메커니즘 자체를 우회하는 데 성공했다는 점에서 심각성이 더해집니다.
SLSA 증명서는 패키지가 신뢰할 수 있는 소스에서 빌드되었음을 암호학적으로 보증하지만, 이 증명서가 생성된 빌드 과정 자체가 악성 코드에 의해 제어되었다면 아무런 의미가 없습니다.
Sigstore는 빌드 프로세스의 유효성만 검증할 뿐, 빌드 대상 코드의 안전성까지는 보장하지 못한다는 점이 명확해진 것입니다.
공격 방식: 3단계 연쇄 취약점
이번 공격은 단일 취약점이 아닌, 세 가지 취약점이 연쇄적으로 작용한 결과입니다.
각 단계별 공격 과정을 상세히 분석해 보겠습니다.
1단계: pull_request_target을 통한 ‘Pwn Request’
공격자는 2026년 5월 10일, TanStack/router 저장소를 포크하여 ‘zblgg/configuration’이라는 이름의 저장소를 생성했습니다.
이후 ‘claude@users.noreply.github.com’이라는 위조된 GitHub App ID를 사용하여 악성 커밋을 푸시했습니다.
‘[skip ci]’라는 접두어를 붙여 CI/CD 파이프라인의 자동 검증을 회피했습니다.
5월 11일, 이 악성 코드가 포함된 풀 리퀘스트(PR)가 TanStack/router의 메인 브랜치로 제출되었습니다.
여기서 TanStack의 bundle-size.yml 워크플로우가 pull_request_target 트리거를 사용하면서 발생한 잘못된 설정이 결정적인 취약점이 되었습니다.
pull_request_target 트리거는 기본 저장소의 보안 컨텍스트에서 실행되는데, 공격자는 이 특성을 이용해 포크된 저장소의 코드를 검증 없이 체크아웃하고 실행시킬 수 있었습니다.
이 기법은 2024년 5월 보안 연구원 Adnan Khan에 의해 Angular, MDN 등에서 처음 보고된 바 있습니다.
2단계: GitHub Actions 캐시 오염
포크된 저장소의 악성 스크립트(vite_setup.mjs)는 즉시 데이터를 유출하지 않았습니다.
대신, pnpm 패키지 저장소를 악성 코드로 미리 오염시켰습니다.
이때 사용된 캐시 키는 이후 합법적인 release.yml 워크플로우에서 사용할 키와 정확히 일치하도록 조작되었습니다.
공격자는 pnpm-lock.yaml 파일의 해시 계산 방식을 파악하여 캐시 키를 미리 생성했고, 이 오염된 1.1GB 용량의 캐시 데이터는 약 8시간 동안 탐지되지 않고 유지되었습니다.
2026년 5월 11일 오후 7시 15분, 합법적인 푸시 이벤트가 release.yml 워크플로우를 트리거하면서 악성 코드가 실행되었습니다.
actions/checkout@v6.0.2 액션의 ref: refs/pull/${{ github.event.pull_request.number }}/merge 옵션은 풀 리퀘스트의 병합된 코드를 가져오도록 설정되어 있었고, 이 과정에서 오염된 pnpm 저장소의 악성 패키지가 설치되었습니다.
3단계: 러너 메모리에서 OIDC 토큰 추출
release.yml 워크플로우는 npm의 OIDC(OpenID Connect) 신뢰 게시자 바인딩에 필요한 id-token: write 권한을 가지고 있었습니다.
악성 코드가 포함된 패키지가 빌드 과정에서 실행되면서, 2025년 3월 tj-actions/changed-files 공격에서 처음 보고된 러너(runner) 메모리에서 OIDC 토큰을 추출하는 기법이 사용되었습니다.
이 추출된 OIDC 토큰은 공격자가 @tanstack 패키지를 자신의 계정으로 등록하고 악성 버전을 배포하는 데 사용되었습니다.
즉, 합법적인 개발 파이프라인의 신뢰받는 ID를 이용하여 악성 패키지를 마치 공식 배포판처럼 위장한 것입니다.
이 과정에서 actions/cache@v5의 post-job save 기능이 워크플로우의 GITHUB_TOKEN이 아닌, 러너 내부 토큰을 사용한다는 점과 캐시 범위가 pull_request_target 실행과 기본 브랜치 푸시 간에 공유된다는 점이 악용되었습니다.
시장 파급 효과 및 한국 시장 전망
이번 TanStack npm 패키지 공격은 전 세계 소프트웨어 개발 생태계에 큰 경종을 울렸습니다.
@tanstack/react-router와 같은 패키지는 월 1,270만 회 이상 다운로드되는 등 개발자들에게 필수적인 라이브러리로 자리 잡고 있기 때문에, 이번 공격으로 인한 파급력은 실로 엄청납니다.
Mistral AI, UiPath와 같은 주요 기업들까지 영향을 받았다는 사실은 소프트웨어 공급망 공격이 대기업뿐만 아니라 스타트업, 개인 개발자까지 예외 없이 타격할 수 있음을 보여줍니다.
특히 국내 IT 업계에도 시사하는 바가 큽니다.
한국은 오픈소스 소프트웨어 의존도가 매우 높으며, 많은 스타트업과 중소기업들이 npm 생태계의 패키지를 적극적으로 활용하고 있습니다.
이번 사태는 국내 개발 환경에서도 보안 감사 및 공급망 관리 강화의 필요성을 다시 한번 부각시킵니다.
이미 정부 차원에서 소프트웨어 공급망 보안 강화 정책을 추진하고 있지만, 이번 사례를 통해 더욱 실질적이고 구체적인 대책 마련이 시급함을 알 수 있습니다.
관련 보안 솔루션이나 컨설팅 시장의 성장 가능성도 엿볼 수 있습니다.
또한, 이번 공격에 사용된 OIDC 토큰 탈취 및 SLSA 증명서 악용 기법은 향후 더욱 정교해질 공격에 대한 방어 전략 수립에 중요한 참고 자료가 될 것입니다.
국내 소프트웨어 공급망 보안 동향을 면밀히 주시해야 할 시점입니다.
전문가 통찰 및 한줄평 (Insight)
이번 TanStack 사태는 소프트웨어 개발의 ‘신뢰’라는 근본적인 가치에 대한 심각한 질문을 던집니다.
합법적인 개발 파이프라인과 신뢰할 수 있는 ID가 공격자에게 악용될 수 있다는 사실은, 우리가 당연하게 여겨왔던 보안 검증 체계에 대한 재검토를 요구합니다.
SLSA와 같은 진보된 보안 메커니즘조차도 공격 대상이 될 수 있다는 점은, 기술의 발전이 언제나 창과 방패의 싸움임을 다시 한번 상기시킵니다.
앞으로는 ‘누가’ 배포했는가 뿐만 아니라 ‘어떻게’ 빌드되었는가, 그리고 ‘어떤 코드’가 빌드되었는가에 대한 다층적인 검증이 더욱 중요해질 것입니다.
개발자들은 더 이상 패키지 사용에 있어 ‘무조건적인 신뢰’를 가져서는 안 되며, 끊임없이 의심하고 검증하는 자세가 필요합니다.
마치 맹목적으로 신뢰했던 ‘샤이-훌루드’처럼, 공급망의 그림자는 생각보다 깊고 넓습니다.
자주 묻는 질문 (FAQ)
Q: 이번 TanStack npm 패키지 공격으로 인해 내 프로젝트가 감염되었는지 어떻게 확인할 수 있나요?
A: 먼저, 영향을 받은 @tanstack/* 버전이 프로젝트의 package.json 및 package-lock.json 파일에 명시되어 있는지 확인해야 합니다.
보안 연구 기관이나 Snyk와 같은 보안 데이터베이스에서 제공하는 영향을 받은 패키지 목록과 버전 정보를 주기적으로 확인하고, 의심스러운 활동이 감지될 경우 즉시 해당 환경의 격리가 필요합니다.
Q: OIDC(OpenID Connect) 토큰이 추출되었다면 어떤 위험이 있나요?
A: OIDC 토큰은 클라우드 환경 등에서 서비스 간의 인증 및 권한 부여에 사용되는 중요한 정보입니다.
이 토큰이 탈취되면 공격자는 해당 토큰으로 부여된 권한을 이용해 클라우드 계정에 접근하거나, 다른 서비스에 대한 악의적인 작업을 수행할 수 있습니다.
따라서 OIDC 토큰이 노출되었다고 판단되면 즉시 토큰을 비활성화하고 재발급받는 등의 긴급 조치가 필수적입니다.
Q: SLSA(Supply-chain Levels for Software Artifacts) 증명서가 있어도 공격이 가능한가요?
A: 네, 가능합니다.
SLSA 증명서는 패키지가 ‘어떻게’ 빌드되었는지에 대한 신뢰성을 제공하지만, ‘빌드된 코드 자체’가 안전한지는 보장하지 않습니다.
공격자가 합법적인 빌드 파이프라인을 장악하여 악성 코드를 빌드하고, 그 과정에서 생성된 SLSA 증명서를 첨부한다면, 증명서 자체는 유효하더라도 패키지는 악성 상태를 유지하게 됩니다.
이는 SLSA의 한계를 보여주는 사례입니다.
Q: 이와 유사한 공격을 방지하기 위해 개발자는 무엇을 할 수 있나요?
A: 개발자는 pull_request_target과 같이 민감한 권한을 가진 CI/CD 워크플로우 설정을 신중하게 검토해야 하며, 외부 소스에서 가져온 코드에 대한 철저한 검증 절차를 마련해야 합니다.
또한, npm 패키지 의존성 관리에 있어 보안 취약점 스캔 도구를 적극 활용하고, 의심스러운 패키지 설치는 피하며, 가능하다면 lock 파일을 사용하여 빌드 재현성을 높이는 것이 중요합니다.
정기적인 보안 교육과 최신 보안 위협 동향 파악 또한 필수적입니다.
출처: https://snyk.io/blog/tanstack-npm-packages-compromised/
관련 추천 상품