Nx S1ngularity 사고: PR 제목에서 npm 토큰 탈취까지
2025년 8월 Nx 사고의 확인된 공격 경로와 악성 버전, 기기 점검 단서, 발급처 조치를 피해 규모 추정 없이 정리했습니다.


목차(13)
목차
2026년 10월 4일 수정. 이전 글은 다운로드 수와 근거가 불분명한 저장소 수를 실제 피해 규모처럼 썼고, 악성 버전을 연속된 구간으로 설명했으며, 검증되지 않은 정리·토큰 교체 스크립트를 실었습니다. 해당 주장과 스크립트를 제거했습니다. 아래 내용은 Nx 보안 공지와 사후 분석을 따르며 유출 피해자 수를 추정하지 않습니다.
2025년 8월 Nx 공급망 사고에서 무슨 일이 있었나요?
2025년 8월 26일 공격자는 탈취한 npm 게시 토큰으로 여러 Nx 패키지의 악성 버전을 배포했습니다. 설치 후 실행되는 코드가 로컬의 민감한 파일을 찾고, 설치된 AI 명령줄 도구의 사용을 시도하고, 수집한 자료를 피해자 GitHub 계정 아래의 공개 저장소로 올렸습니다. Nx에 따르면 악성 패키지는 약 4시간 동안 게시돼 있었습니다. 해당 버전을 그 기간에 설치했다면 조사해야 하지만, 설치 사실만으로 특정 컴퓨터에서 어떤 자료가 유출됐는지 알 수는 없습니다.
PR 제목이 어떻게 npm 게시 토큰까지 이어졌나요?
Nx에 따르면 PR 제목 검사 워크플로가 외부 입력인 제목을 셸 스크립트에 직접 넣었습니다. 이 워크플로는 pull_request_target으로 실행됐고 읽기·쓰기 권한의 GITHUB_TOKEN을 갖고 있었습니다. 공격자는 이 권한으로 게시 스크립트를 바꾼 브랜치를 만들고 workflow_dispatch로 publish.yml을 실행했습니다. 게시 작업에는 npm 토큰이 있었고 바뀐 스크립트가 이를 외부로 보냈습니다. 탈취한 토큰으로 정상 배포 절차 밖에서 악성 패키지를 게시했습니다.
경고를 받은 뒤 기본 브랜치의 취약한 워크플로는 되돌렸지만, 오래된 대상 브랜치에는 남아 있었습니다. Nx 보안 공지는 앞선 경고, 8월 24일의 악용, 8월 26일의 npm 배포를 별도 사건으로 기록합니다. GitHub는 신뢰할 수 없는 입력을 인라인 셸 코드에 직접 넣지 말고 GITHUB_TOKEN의 권한을 제한하라고 안내합니다.
어떤 버전이 악성이었나요?
Nx 공지는 시작과 끝 사이의 모든 버전이 아니라 특정 버전을 나열합니다. nx는 20.9.0, 20.10.0, 20.11.0, 20.12.0, 21.5.0, 21.6.0, 21.7.0, 21.8.0입니다. @nx/devkit, @nx/js, @nx/workspace, @nx/node는 20.9.0과 21.5.0, @nx/eslint는 21.5.0, @nx/key와 @nx/enterprise-cloud는 3.2.0입니다. 각 패키지의 영향 여부를 판단할 때는 최신 보안 공지와 실제 설치 기록을 함께 확인하세요.
Nx Console이 버전을 확인하면서 최신 nx 패키지를 설치할 수도 있었다고 Nx는 밝혔습니다. 악성 버전이 최신으로 지정됐던 시간에는 명시적인 nx 설치 명령 없이도 추가 설치 경로가 생긴 셈입니다. 특정 개발 환경이 영향을 받았는지는 설치 패키지와 로그로 확인해야 합니다.
악성 패키지는 무엇을 했나요?
Nx 공지에 따르면 설치 후 실행되는 코드가 로컬 텍스트 파일과 자격증명을 찾고, GitHub CLI로 이름에 s1ngularity-repository가 들어간 저장소를 만들었습니다. 로컬 AI 명령줄 도구 호출도 시도했고, 셸 시작 파일에 종료 명령을 추가했습니다. AI 도구가 설치돼 있었다는 사실만으로 악성 코드 실행이나 민감 정보 반환을 입증할 수는 없습니다.
예상치 못한 공개 저장소, /tmp/inventory.txt 파일, GitHub 계정 활동, .bashrc·.zshrc의 이상한 명령은 점검 단서입니다. 어느 하나만으로 유출된 시크릿 전체를 알 수 없고, 단서 하나가 보이지 않는다고 악성 버전을 설치한 기기가 안전하다고 단정할 수도 없습니다. 패키지 설치 기록과 활동 로그, 접근 가능했을 자격증명의 발급처 상태를 함께 봅니다.
조직은 무엇을 확인하고 조치해야 하나요?
1. 설치와 노출 범위를 확인합니다
잠금 파일, 설치된 패키지 버전, CI 로그, 개발 기기의 설치 기록과 실행 시각을 Nx 공지의 패키지별 목록에 대조합니다. Nx Console이 최신 버전을 받아왔을 수 있는 편집기 환경도 포함합니다. 패키지 삭제나 셸 파일 수정보다 먼저 관련 로그와 기기 증거를 보존합니다. 사고 글에서 복사한 “일괄 정리” 스크립트를 그대로 실행하지 않습니다.
2. 공개된 침해 단서를 찾습니다
영향받은 GitHub 계정의 보안 로그에서 예상치 못한 저장소 생성과 s1ngularity-repository가 포함된 이름을 확인합니다. /tmp/inventory.txt와 .bashrc·.zshrc의 수상한 변경도 살핍니다. Nx에 따르면 GitHub가 유출 저장소를 이미 숨기거나 삭제했을 수 있으므로, 현재 저장소 목록에 없다는 사실만으로 제외할 수 없습니다.
3. 발급처에서 자격증명을 막습니다
악성 코드가 작동하는 자격증명을 읽을 수 있었다면 담당자가 해당 계정, 접근 범위, 종속 작업, 사용 기록을 확인하고 발급처에서 교체하거나 폐기합니다. 패키지 게시, 클라우드 자원 접근, 다른 키 발급이 가능한 권한을 우선 살핍니다. Nx 안내에 따라 GitHub CLI 접근도 교체합니다. 변경 후 종속 서비스가 작동하는지 시험하고 로그가 부족해 알 수 없는 부분은 그대로 기록합니다.
4. 설치 경로를 정리합니다
환경에 맞는 패키지 관리자와 공급업체 지침을 따라 해당 버전과 캐시를 정리하고 검증된 안전 버전을 설치합니다. 셸 시작 파일에 공지된 명령이 추가됐는지도 확인합니다. Nx는 게시 절차를 npm Trusted Publishers로 옮기고 수동 승인과 출처 확인을 추가했습니다. 이 방식은 해당 작업에서 장기 유효 npm 게시 토큰을 없애지만, 앞으로의 모든 패키지 안전성을 자동으로 보장하지는 않습니다.
Cremit은 이 조사에서 무엇을 도울 수 있나요?
Cremit은 지원하는 연결 소스에서 노출 자격증명을 찾고, 지원 유형을 발급처에 확인하며, 제공 가능한 AWS 액세스 키·GCP API 키 정보를 보여주고 조치 담당자를 지정할 수 있습니다. 악성 npm 패키지의 설치를 탐지하거나 악성 코드가 읽은 모든 파일을 재구성하거나 유출을 입증하거나 모든 발급처 키를 자동 교체하지는 않습니다. 패키지와 기기 증거는 사고 담당자가 관리하고, 자격증명 발견 결과는 발급처 조사에 활용합니다.
사고 뒤 무엇이 바뀌었나요?
Nx는 악성 버전을 제거하고 npm 게시 토큰을 폐기했으며, 배포와 외부 기여자 워크플로의 승인 절차를 강화하고 npm Trusted Publishers를 도입했다고 밝혔습니다. 이 사고에서 확인할 경계는 구체적입니다. 외부 PR 제목이 권한 높은 워크플로 코드에 들어갔고, 쓰기 가능한 저장소 토큰이 게시 작업에 닿았고, 장기 유효 npm 토큰으로 패키지를 게시할 수 있었습니다. 자신의 배포 절차에서도 각 경계를 확인해야 합니다.
함께 읽을 글
OWASP NHI5: 머신 계정의 과도한 권한 확인하기
근거 자료
Nx — GHSA-cxm3-wv7p-598c 보안 공지와 타임라인
이어서 읽기
노출된 API 키 뒤의 머신 접근을 확인하는 법
노출된 키는 조사 단서입니다. 발급처, 계정, 권한, 사용 작업, 담당자를 찾아 접근 경로를 닫는 순서입니다.
보안 스캐너가 해킹 도구가 된 날: Trivy 공급망 공격의 사이버 킬체인 분석
Aqua Security의 Trivy가 해킹당해 LiteLLM까지 연쇄 감염된 TeamPCP 공급망 공격. 사이버 킬체인 7단계와 MITRE ATT&CK 매핑으로 분석하고, NHI 거버넌스 실패가 만든 연쇄 재앙의 교훈을 정리합니다.
파일은 삭제됐는데 키는 활성이라면: Zombie Key 조사
파일을 지워도 키는 폐기되지 않습니다. 발급처, Git 기록, 담당자, 마지막 유효성 확인 결과를 함께 살펴야 합니다.
다음 글을 메일로 받아보세요
Cremit의 월간 자격증명 보안 브리프. 한 통에 핵심만 담습니다.