8월 4일 오전 9시(UTC) 경, 공격자가 Jared Wray(jaredwray)의 GitHub 계정을 장악했습니다. 이 접근 권한을 이용해 keyv 저장소의 main 브랜치에 직접 악성 코드를 푸시하고 즉시 전체 keyv 및 cacheable 패키지 제품군의 새 릴리스를 배포했습니다.
초기 감염에는 두 네임스페이스의 11개 패키지가 포함되었습니다: keyv, cacheable-request, cache-manager, @cacheable/utils, flat-cache, file-entry-cache 등. Aikido Security, StepSecurity(이 웜을 "ChainDrop"으로 추적), Socket, Chainguard의 보안 연구원들은 첫 몇 시간 내에 독립적으로 이 침해 사실을 확인했습니다.
모든 감염된 패키지는 동일한 감염 패턴을 보였습니다: 두 개의 새 파일(setup.mjs와 Math_Symbol.js)과 각 package.json에 추가된 "preinstall": "node setup.mjs" 항목입니다.
개발자나 CI 시스템이 npm install을 실행하면, 설치가 완료되기 전에 setup.mjs 드로퍼가 자동으로 실행되었습니다. 이 드로퍼의 역할은 GitHub Releases에서 정식 Bun JavaScript 런타임 바이너리를 다운로드한 후, 난독화된 2단계 페이로드(Math_Symbol.js, 약 710~728KB)를 실행하는 것이었습니다.
Microsoft Threat Intelligence는 이 페이로드가 Mini Shai-Hulud 변종임을 확인했습니다. 이 페이로드는 감염된 환경으로부터 광범위한 자격 증명과 시크릿을 수집합니다:
이 공격을 특히 위험하게 만든 것은 자가 증식 능력이었습니다. 감염된 환경에서 npm 발행 토큰과 GitHub PAT를 탈취한 후, 웜은 이 접근 권한을 사용하여 다른 무관한 메인테이너가 소유한 다른 패키지의 추가 악성 버전을 게시했습니다.
침해 범위는 빠르게 확대되었습니다:
웜은 네임스페이스 경계를 넘어 확산되었습니다. 시작된 keyv/cacheable 제품군에 머물지 않고, Deliveroo, Ornikar, OneReach, Picsart, Qlik, ServiceTitan 등 주요 조직이 소유한 패키지로까지 이동했습니다.
탈취된 자격 증명은 공격자가 제어하는 GitHub 저장소로 유출되었습니다. 웜은 이 목적을 위해 새로운 저장소를 생성하거나 전용 유출 저장소를 사용했습니다. 페이로드에는 여러 개의 중복 유출 채널이 내장되어 있어, 단일 채널이 차단되어도 복원력을 유지했습니다.
여러 보안 업체의 연구원들은 영향을 받은 패키지를 접촉한 모든 시스템을 완전히 손상된 것으로 간주할 것을 촉구했습니다. 다음은 일관되게 권장된 대응 조치 단계입니다:
npm/yarn/pnpm 오버라이드(예: package.json의 "overrides")를 사용하여 감염된 버전이 실수로 재설치되는 것을 방지하십시오. 전이적(transitive) 의존성을 포함하여 package-lock.json, yarn.lock, pnpm-lock.yaml 파일에서 영향을 받은 패키지 버전이 있는지 확인하십시오.
영향을 받은 버전에서 npm install을 실행한 시스템에서 단순히 악성 파일을 삭제하는 것으로 끝내지 마십시오. 해당 호스트에 존재하는 모든 시크릿이 손상된 것으로 가정하십시오.
잠재적으로 노출된 모든 자격 증명을 취소하고 재생성하십시오:
매우 중요한 세부 사항입니다. 이 멀웨어는 때때로 GitHub 워크플로우 감시자를 설정하여 새 토큰이 생성되는 순간 다시 노출시킬 수 있습니다. 연구원들은 자격 증명을 교체하기 전에 모니터링 서비스를 비활성화하거나 제거할 것을 권고했습니다.
개발자 시스템과 CI/CD 러너 모두에서 npm/pnpm/yarn 캐시와 Docker 빌드 캐시를 지우십시오. 오염된 의존성이 빌드 캐시나 Docker 레이어에 남아있지 않도록 모든 아티팩트를 처음부터 재빌드하십시오.
새로 생성된 저장소나 승인되지 않은 워크플로우를 찾으십시오. 웜이 생성했을 수 있는 .claude/settings.json 또는 .vscode/tasks.json과 같은 지속성 아티팩트가 있는지 확인하십시오.
2026년 8월 4일의 샤이훌루드 웜 공격은 JavaScript 생태계 보안에 있어 중요한 분기점이었습니다. 이는 단일 메인테이너 계정이 손상되어 — 대부분의 영향을 받은 패키지에 직접적인 접근 권한이 없었음에도 불구하고 — 몇 시간 만에 천 개 이상의 패키지를 감염시키는 웜으로 이어질 수 있음을 보여주었습니다. 이 공격이 페이로드 실행을 위해 정식 Bun 런타임 바이너리를 사용하고, 탈취된 토큰을 통한 자가 증식, 그리고 중복 유출 채널을 사용했다는 점은 이전의 공급망 공격보다 더 정교했습니다.
엔지니어링 및 보안 팀에게 이 사건은 의존성 고정, 가능한 경우 사전/사후 설치 스크립트 비활성화, 비정상적인 GitHub 활동 모니터링, 그리고 공급망 침해에 대한 사고 대응 플레이북 유지의 중요성을 강조합니다.