TanStack npm 공급망 공격 사후 분석 보고서
2026년 5월 11일, 공격자가 깃허브 액션스(GitHub Actions)의 취약점을 악용하여 TanStack의 42개 npm 패키지에 멀웨어를 배포하는 공급망 공격을 감행했습니다. 이 악성 코드는 패키지 설치 시 사용자의 클라우드(AWS, GCP 등) 및 SSH 인증 정보를 탈취하여 외부로 유출하며, 감염된 계정을 통해 추가적으로 자가 전파되는 특징을 가집니다. 외부 보안 연구원에 의해 20분 만에 신속히 탐지되었으나, 해당 시간대에 영향을 받은 버전을 설치한 개발자는 즉시 설치 환경을 격리하고 모든 핵심 인증 정보를 교체해야 합니다.
TanStack Search... K 자동 로그인 Start RC Start RC Router Router Query Query Table Table DB beta DB beta AI alpha AI alpha Form new Form new Virtual Virtual Pacer beta Pacer beta Hotkeys alpha Hotkeys alpha Store alpha Store alpha Devtools alpha Devtools alpha CLI alpha CLI alpha Intent alpha Intent alpha 라이브러리 더보기 라이브러리 더보기 Builder Alpha Builder Alpha 블로그 블로그 유지보수자 유지보수자 파트너 파트너 쇼케이스 쇼케이스 학습하기 NEW 학습하기 NEW 통계 통계 유튜브 유튜브 디스코드 디스코드 굿즈 굿즈 지원 지원 깃허브 깃허브 이념 이념 원칙 원칙 브랜드 가이드 브랜드 가이드 블로그 이 페이지에서 사후 분석: TanStack npm 공급망 침해 사건 페이지 복사 작성자: Tanner Linsley, 2026년 5월 11일. 마지막 업데이트: 2026-05-11
TL;DR # 2026년 5월 11일 19:20 UTC부터 19:26 UTC 사이에 공격자는 다음 기법들을 조합하여 42개의 @tanstack/* npm 패키지에 걸쳐 84개의 악성 버전을 게시했습니다. pull_request_target을 활용한 'Pwn Request(악의적 PR)' 패턴, 포크(fork)↔베이스(base) 간 신뢰 경계를 넘어선 깃허브 액션스 캐시 오염(Cache Poisoning), 깃허브 액션스 러너 프로세스의 런타임 메모리에서 OIDC 토큰을 추출하는 기법이 사용되었습니다. npm 토큰은 탈취되지 않았으며 npm 게시 워크플로우 자체도 침해되지 않았습니다.
이 악성 버전들은 stepsecurity 소속 외부 보안 연구원인 ashishkurmi에 의해 20분 만에 공개적으로 탐지되었습니다. 영향을 받은 모든 버전은 더 이상 사용되지 않도록(deprecated) 조치되었으며, npm 레지스트리에서 파일을 강제로 삭제하기 위해 npm 보안팀과 협력 중입니다. npm 자격 증명이 탈취되었다는 증거는 없지만, 2026년 5월 11일에 영향을 받은 버전을 설치한 사용자는 설치한 호스트에서 접근 가능한 AWS, GCP, Kubernetes, Vault, GitHub, npm 및 SSH 자격 증명을 모두 교체(rotate)할 것을 강력히 권장합니다.
추적 이슈: TanStack/router#7383 깃허브 보안 권고문: GHSA-g7cv-rxg3-hmpx
영향 범위 # 영향을 받은 패키지 # 42개 패키지, 84개 버전 (패키지당 2개씩, 약 6분 간격으로 게시됨). 전체 목록은 추적 이슈에서 확인하십시오. 확인 결과 안전한 패키지 군: @tanstack/query*, @tanstack/table*, @tanstack/form*, @tanstack/virtual*, @tanstack/store, @tanstack/start (메타 패키지로서, @tanstack/start-* 제외).
멀웨어의 행동 방식 # 개발자 또는 CI(지속적 통합) 환경이 영향을 받는 버전에 대해 npm install, pnpm install 또는 yarn install을 실행하면, npm은 악성 optionalDependencies 항목을 해석하고, 포크 네트워크에서 분리된 페이로드 커밋(orphan payload commit)을 가져와서 prepare 라이프사이클 스크립트를 실행하고, 영향을 받은 tarball 안에 밀반입된 난독화된 약 2.3 MB 크기의 router_init.js를 실행합니다.
해당 스크립트는 다음과 같은 일반적인 위치에서 자격 증명을 수집합니다:
AWS IMDS / Secrets Manager, GCP 메타데이터, Kubernetes 서비스 계정 토큰, Vault 토큰, ~/.npmrc, GitHub 토큰 (환경변수, gh CLI, .git-credentials), SSH 개인 키
Session/Oxen 메신저의 파일 업로드 네트워크(filev2.getsession.org, seed{1,2,3}.getsession.org)를 통해 데이터를 외부로 유출합니다. 종단 간 암호화가 적용되어 공격자가 제어하는 C2(명령 제어) 서버가 없으므로 IP/도메인을 차단하는 것이 유일한 네트워크 완화 방법입니다.
자가 전파(Self-propagates): registry.npmjs.org/-/v1/search?text=maintainer:
타임라인 # 모든 시간은 UTC 기준입니다. 깃허브 API 및 npm 레지스트리의 로컬 타임스탬프.
공격 전 (캐시 오염 단계) # 시간 / 이벤트 2026-05-10 17:16 / 공격자가 github.com/zblgg/configuration 포크를 생성합니다. (TanStack/router를 포크한 것으로, 포크 목록 검색을 피하기 위해 고의로 이름이 변경됨) 2026-05-10 23:29 / 조작된 신원인 claude claude@users.noreply.github.com가 포크에 악성 커밋 65bf499d16a5e8d25ba95d69ec9790a6dd4a1f14을 작성합니다. (약 30,000줄의 번들링된 JS 페이로드인 packages/history/vite_setup.mjs를 추가함). 푸시 이벤트 시 CI가 실행되지 않도록 커밋 메시지에 [skip ci]를 접두어로 붙임. 2026-05-11 ~10:49 / zblgg가 TanStack/router#main에 대해 "WIP: simplify history build"라는 제목으로 PR #7378을 엽니다. 2026-05-11 10:49 이후 / bundle-size.yml 및 labeler.yml (모두 pull_request_target)이 자동으로 실행됨