
Nx, 2025년 8월 26일
빌드 도구 Nx의 npm 게시 토큰이 GitHub Actions 워크플로 인젝션으로 유출됐고, 공격자는 몇 시간 동안 악성 버전을 올렸습니다. nx 20.9.0부터 20.12.0, 21.5.0부터 21.8.0과 여러 @nx/* 패키지가 영향을 받았습니다. 악성 버전에는 postinstall로 실행되는 telemetry.js가 들어 있었습니다.
이 스크립트는 정찰 방식 때문에 화제가 됐습니다. PC에 Claude Code, Gemini CLI, Amazon Q CLI가 설치돼 있으면 권한 확인을 끄는 옵션(--dangerously-skip-permissions, --yolo, --trust-all-tools)으로 실행해 지갑 파일, SSH 키, .env 같은 파일 경로를 찾게 했습니다. 수집한 내용은 피해자 GitHub 계정에 s1ngularity-repository로 시작하는 공개 저장소를 만들어 올렸습니다. AI 도구가 그 요청을 실제로 수행했는지는 분석한 곳마다 의견이 갈립니다. Nx는 사후 분석에서 악성 버전에 npm 출처 증명(provenance)이 없다는 점으로 이상을 알아챘다고 밝혔습니다.
Shai-Hulud, 2025년 9월
한 달 뒤에는 스스로 퍼지는 웜이 나왔습니다. CISA는 9월 23일 경보에서 500개가 넘는 npm 패키지가 감염됐다고 밝혔습니다. 설치 시점에 GitHub 토큰과 클라우드 키를 수집하고, 훔친 npm 자격증명으로 피해자가 관리하는 다른 패키지에 자신을 끼워 넣는 방식이었습니다. CISA는 중첩 의존성과 사내 아티팩트 저장소에 캐시된 사본까지 포함해 의존성을 점검하라고 권고했습니다.
두 사건 모두 개발자가 한 일은 평소처럼 npm install을 실행한 것이 전부였습니다. 코드 리뷰로는 막을 수 없는 지점입니다.
설치 스크립트는 기본으로 막습니다
효과가 가장 큰 조치는 의존성의 설치 스크립트를 기본으로 실행하지 않는 것입니다. pnpm은 10.0부터 의존성의 lifecycle 스크립트를 기본으로 실행하지 않고, onlyBuiltDependencies에 적은 패키지만 허용합니다. npm은 설정으로 끌 수 있습니다.
# npm: 설치 스크립트 끄기 npm config set ignore-scripts true # 이 사용자의 모든 설치에 적용 npm ci --ignore-scripts # CI에서 한 번만 # pnpm 10 이상: 스크립트가 필요한 패키지만 허용 (pnpm-workspace.yaml) onlyBuiltDependencies: - esbuild - sharp
스크립트를 끄면 네이티브 모듈처럼 설치 때 빌드가 필요한 패키지가 깨집니다. 처음 며칠은 실패하는 패키지를 모아 허용 목록을 만드는 데 시간이 듭니다. 이 설정도 완전하지는 않습니다. 악성 코드가 라이브러리 본문에 들어 있으면 설치 때는 조용하다가 처음 require하는 순간 실행됩니다.
처음 들이는 버전은 빈 환경에서 먼저
그래서 새로 들이는 패키지나 메인테이너가 바뀐 패키지는 비밀값이 없는 환경에서 먼저 설치해 봅니다. 가장 간단한 형태는 아무것도 마운트하지 않은 컨테이너입니다.
# 예시: 홈 디렉터리와 토큰이 없는 컨테이너에서 설치하고, 스크립트 출력을 남기기
docker run --rm node:22 \
sh -c "mkdir /tmp/t && cd /tmp/t && npm init -y >/dev/null && \
npm install 대상패키지@버전 --foreground-scripts 2>&1" | tee install.log
이렇게 하면 설치 스크립트가 어떤 명령을 실행하는지, 어디로 접속하려 하는지 정도는 보입니다. 특정 CI 환경변수가 있을 때만 움직이거나 정해진 날짜 이후에만 동작하는 코드는 빈 컨테이너에서 조용히 지나갈 수 있습니다.
Genox에서는 Vulnerability Scanner가 메인테이너 변경이나 난독화 같은 위험 신호를 찾으면 Behavioral Analyzer 샌드박스에서 설치 과정을 실행해 환경변수 접근과 외부 통신을 확인합니다. 이 단계도 위와 같은 한계가 있어서, 설치 스크립트 차단과 함께 쓰는 것을 전제로 합니다.
이미 설치했다면
영향 버전을 설치한 적이 있다면 그 PC나 CI 러너에서 접근할 수 있던 토큰부터 교체합니다. npm, GitHub, 클라우드 키가 우선입니다. GitHub 조직에서 s1ngularity-repository나 Shai-Hulud라는 이름의 저장소, .github/workflows/shai-hulud-workflow.yml 파일이 생겼는지 찾아보세요. Nx 건은 ~/.bashrc와 ~/.zshrc에 sudo shutdown -h 0 줄을 추가했으니 이것도 지웁니다.


