---
title: "Nx npm 침해: 개발자의 Mac에서 한 일과 Kilobat이 표시했을 내용"
url: "https://kilobat.app/ko/incidents/nx-s1ngularity"
description: "2025년 8월 악성 Nx 버전이 설치된 AI CLI를 사용해 비밀 정보를 찾고 GitHub로 전송한 방법과 Kilobat이 탐지할 수 있었던 것과 없었던 것을 알아봅니다."
---

보안 사고 · npm 패키지 침해

# Nx npm 침해: 개발자의 Mac에서 한 일과 Kilobat이 표시했을 내용

2025년 8월 26일과 27일 약 5시간 동안 npm의 Nx 빌드 시스템 여덟 버전에는 개발자의 컴퓨터에서 비밀 정보를 검색하는 postinstall 스크립트가 포함되어 있었습니다. 이 스크립트는 발견한 AI 코딩 CLI의 도움을 받아 수집한 정보를 피해자의 GitHub 계정에 새로 만든 공개 저장소에 게시했습니다.

발생 시기: 2025년 8월 26~27일 · 출처 확인: 2026년 11월 1일

## 요약

- [보호](https://kilobat.app/ko/mac-malware-blocker): 도움이 되지 않음

  차단할 대상이 없습니다. 코드는 registry.npmjs.org에서 왔고 데이터는 api.github.com으로 전송되었으며 어떤 위협 목록에도 두 호스트가 없습니다.
- [에이전트 보호](https://kilobat.app/ko/mac-malware-blocker): 도움이 되지 않음

  붙여넣기 사이트, 터널 또는 IP 주소는 사용되지 않았으며 업로드 차단 기능은 설계상 api.github.com 같은 잘 알려진 호스트를 차단하지 않습니다.
- [에이전트 네트워크 로그](https://kilobat.app/ko/ai-coding-agents): 제한적

  GitHub API에 연결한 설치 스크립트와 스크립트가 시작한 AI CLI 실행을 기록했을 것입니다. 다만 이 Mac에서 이루어진 설치만 기록하며 차단하지는 않습니다.

## 발생한 일

공격자는 프로젝트 자체 CI를 통해 Nx의 npm 게시 토큰을 얻었습니다. [유지관리자의 보안 권고](https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c)에 따르면 8월 21일 병합된 GitHub Actions 워크플로가 `pull_request_target` 트리거를 사용하고 풀 리퀘스트 제목을 셸에 출력했기 때문에 조작된 제목으로 저장소 권한을 가진 명령어를 실행할 수 있었습니다. 8월 24일 이 경로를 이용해 악성 커밋에서 게시 워크플로를 시작하고 npm 토큰을 웹훅으로 보냈습니다.

공격자는 토큰으로 `nx` 20.9.0~20.12.0 및 21.5.0~21.8.0과 `@nx/devkit`, `@nx/js`, `@nx/workspace`, `@nx/node`, `@nx/eslint`, `@nx/key`, `@nx/enterprise-cloud`의 여러 버전을 게시했습니다. 각각에는 `telemetry.js`를 실행하는 `postinstall` 훅이 포함되어 있었으며 이 코드는 macOS와 Linux에서만 동작했습니다.

스크립트는 `claude`, `gemini`, `q` 명령줄 도구를 찾아 설치된 경우 권한 확인을 건너뛰는 플래그(`--dangerously-skip-permissions`, `--yolo`, `--trust-all-tools`)와 함께 실행했습니다. 프롬프트는 지갑, 키 및 `.env` 파일처럼 보이는 파일을 `/tmp/inventory.txt`에 나열하도록 요청했습니다. [Snyk](https://snyk.io/blog/weaponizing-ai-coding-agents-for-malware-in-the-nx-malicious-package/)와 [StepSecurity](https://www.stepsecurity.io/blog/supply-chain-security-alert-popular-nx-build-system-package-compromised-with-data-stealing-malware)가 코드를 공개했습니다. [Wiz](https://www.wiz.io/blog/s1ngularity-supply-chain-attack)는 수백 건에서 이 방식이 성공했으며 일부는 AI 제공업체의 안전장치에 의해 거부되었다고 관찰했습니다.

이어 해당 파일을 읽고 `gh auth token`로 GitHub CLI 토큰과 `~/.npmrc`에서 npm 토큰을 수집한 뒤 피해자 계정에 `s1ngularity-repository`라는 공개 저장소를 만들어 모든 것을 세 번 base64로 인코딩한 `results.b64`로 업로드했습니다. 또한 `~/.zshrc`와 `~/.bashrc`에 `sudo shutdown -h 0`를 추가해 새 터미널을 열 때마다 암호를 묻고 컴퓨터를 종료하게 했습니다.

많은 설치는 누군가 직접 입력한 것이 아니었습니다. 유지관리자는 Nx Console 편집기 확장 프로그램 버전 18.6.30~18.65.1이 시작할 때 최신 `nx`를 확인한다는 사실을 발견했습니다. 따라서 해당 시간에 편집기를 열기만 해도 충분했습니다. Wiz는 CI 파이프라인에서도 악성코드가 실행되는 것을 발견했습니다. Wiz는 유출된 데이터에서 유효한 GitHub 토큰을 1,000개 이상 확인했으며 두 번째 단계에서는 탈취한 토큰으로 5,500개가 넘는 비공개 저장소를 공개했습니다.

## 타임라인

1. 2025년 8월 21일

   셸 인젝션 결함이 있는 워크플로가 Nx 저장소에 병합됩니다(유지관리자 보안 권고).
2. 2025년 8월 24일

   조작된 풀 리퀘스트가 악성 커밋에서 게시 워크플로를 시작하고 npm 토큰을 웹훅으로 보냅니다.
3. 8월 26일 22:32 UTC

   `nx` 21.5.0 및 여러 `@nx/*` 패키지가 `telemetry.js`와 함께 게시되고, 7분 후 20.9.0이 뒤따릅니다.
4. 8월 27일 00:30 UTC

   사용자가 악성 버전에 대한 GitHub 이슈를 엽니다. 마지막 두 버전 21.8.0과 20.12.0은 00:37에 나타납니다.
5. 8월 27일 02:44 UTC

   npm이 영향을 받은 버전과 게시 토큰을 제거합니다.
6. 8월 27일 약 09:00 UTC

   GitHub가 공격자가 만든 저장소를 비활성화합니다. 첫 저장소가 나타난 지 약 8시간 뒤입니다(Wiz).
7. 2025년 8월 27일

   Nx Console 18.66.0이 최신 `nx` 설치를 중단합니다. Nx는 게시 방식을 2FA를 사용하는 npm Trusted Publishers로 옮깁니다.
8. 2025년 8월 28~29일

   탈취된 토큰으로 비공개 저장소의 이름을 바꾸고 공개합니다. Wiz는 400개 이상의 계정과 5,500개의 저장소를 집계했습니다.

## 네트워크에서 보인 모습

Mac에서 이 공격은 개발자의 컴퓨터가 매일 연결하는 두 호스트를 사용했습니다. 패키지는 다른 패키지처럼 `registry.npmjs.org`에서 왔습니다. 탈취 데이터는 피해자의 GitHub CLI 토큰을 사용해 피해자 자격으로 `api.github.com`에 전송되었습니다. 저장소를 만드는 `POST /user/repos` 다음에 인코딩된 데이터를 담은 `PUT /repos/<owner>/s1ngularity-repository/contents/results.b64`가 이어졌습니다. 명령 및 제어 서버나 다른 업로드 목적지는 없었습니다.

프로세스 트리는 짧았습니다. `npm`(또는 편집기 확장 프로그램)이 셸을 실행하고 셸은 `node telemetry.js`를 실행했으며 node가 자식 프로세스로 `claude`, `gemini` 또는 `q`를 시작했습니다. 각 AI CLI는 평소처럼 자체 제공업체와 통신했고 파일 읽기는 로컬에서 이루어졌습니다. 업로드 자체는 node에서 이루어졌으며 크기는 파일의 내용에 전적으로 좌우되었습니다.

## 침해 지표

출처에 기록된 그대로입니다. 도메인은 링크가 아닌 텍스트이며 출처가 무해화한 경우 그대로 무해화했습니다(`[.]`). 이 인프라는 대부분 오래전에 사라졌습니다. 지표는 현재 캠페인을 차단하기보다 오래된 로그, 파일 및 계정을 확인하는 데 도움이 됩니다.

| 지표 | 유형 | 표시 위치 | 참고 |
|---|---|---|---|
| `api.github.com` | 호스트(정상) | 내 Mac | npm 설치 중 node가 만든 `POST /user/repos` 다음 `PUT …/contents/results.b64`. |
| `s1ngularity-repository, s1ngularity-repository-0, s1ngularity-repository-1` | GitHub 저장소 이름 | GitHub 계정 | 생성 시 공개 상태였으며 GitHub가 8월 27일 비활성화했습니다. 두 번째 단계에서 이름이 변경된 저장소에는 `s1ngularity-repository-` 뒤에 다섯 글자가 사용되었습니다. |
| `results.b64` | 파일 | GitHub 저장소 | 수집된 데이터로, base64로 두세 번 인코딩되었습니다. |
| `/tmp/inventory.txt, /tmp/inventory.txt.bak` | 파일 | 내 Mac | AI CLI가 만든 파일 경로 목록. |
| `sudo shutdown -h 0` | ~/.zshrc, ~/.bashrc의 줄 | 내 Mac | 터미널을 열고 암호를 입력하면 Mac을 종료합니다. |
| `nx 20.9.0–20.12.0, 21.5.0–21.8.0` | npm 버전 | 잠금 파일, npm 캐시 | `@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도 해당합니다. |

## Kilobat이 표시하거나 차단했을 내용

- **[에이전트 네트워크 로그](https://kilobat.app/ko/ai-coding-agents).** Claude Code가 `npm install`를 실행하는 것처럼 에이전트가 설치를 수행한 경우, 세션에는 설치 중 `npm` 아래의 `node`가 `api.github.com`로 전송하는 모습이 기록됩니다. 설치 스크립트가 GitHub API와 통신한다면 살펴볼 만합니다. api.github.com은 잘 알려진 호스트이므로 *처음*으로 표시되지 않으며 10 MB를 초과한 경우에만 *대용량 업로드*로 표시됩니다.
- **[에이전트 네트워크 로그](https://kilobat.app/ko/ai-coding-agents).** Kilobat은 Claude Code와 Gemini CLI를 시작한 주체가 아니라 실행 파일로 인식합니다. 따라서 스크립트가 시작한 실행은 사용자가 에이전트를 시작하지 않은 시점에 프로젝트 폴더에서 별도 세션으로 나타납니다. Amazon의 `q`는 Kilobat이 인식하는 에이전트에 속하지 않습니다.
- **[보호](https://kilobat.app/ko/mac-malware-blocker).** 차단할 것이 없습니다. registry.npmjs.org와 api.github.com은 위협이 아니며 Kilobat이 차단해서는 안 됩니다.
- **[에이전트 가드](https://kilobat.app/ko/mac-malware-blocker).** 역시 감지하지 못합니다. 가드의 규칙은 붙여넣기 사이트, 파일 공유, 터널, 요청 수집기 및 원시 IP 주소를 다루지만 이 중 어느 것도 나타나지 않았습니다. 또한 업로드 차단은 잘 알려진 호스트를 제외하므로 `git push`가 계속 작동합니다.

## Kilobat이 도움이 되지 않았을 경우

- 피해자 자신의 토큰으로 github.com에 데이터를 유출하는 행위는 정상적인 GitHub CLI 작업과 같아 보입니다. Kilobat은 호스트와 바이트 수만 확인하며 전송된 내용은 확인하지 않습니다.
- npm 토큰은 GitHub 러너에서 실행된 Nx의 GitHub Actions에서 탈취되었고, 두 번째 단계는 공격자 측에서 탈취한 토큰으로 실행되었습니다. 어느 쪽도 Mac에 접촉하지 않았습니다.
- VS Code의 편집기 확장 프로그램이 시작한 설치는 에이전트에 귀속되지 않아 에이전트 세션이 생성되지 않습니다. Cursor와 Windsurf에서는 해당 앱의 작업으로 집계됩니다.
- 파일 읽기, AI CLI의 파일 검색 실행 및 `~/.zshrc` 편집은 네트워크 이벤트가 아닙니다.
- 에이전트 네트워크 로그는 30일 동안 보관되므로 2025년 8월에 이 코드가 Mac에서 실행되었는지 지금 확인할 수 없습니다.

## 지금 Mac 확인하기

1. 각 프로젝트에서 영향을 받은 Nx 버전이 설치되어 있는지 확인하고 설치되어 있다면 업데이트하세요.

   ```
   npm ls nx
   ```
2. 스크립트가 남긴 파일을 찾으세요. macOS는 재시작할 때 `/tmp`를 지우므로 파일이 없다고 해서 많은 것을 증명하지는 못합니다.

   ```
   ls -la /tmp/inventory.txt /tmp/inventory.txt.bak
   ```
3. 셸 시작 파일에서 종료 명령줄을 찾고 있다면 삭제하세요.

   ```
   grep -n "shutdown" ~/.zshrc ~/.bashrc
   ```
4. GitHub 보안 로그에서 이름에 `s1ngularity-repository`가 포함된 `repo.create` 이벤트를 찾으세요: [github.com/settings/security-log](https://github.com/settings/security-log?q=action%3Arepo.create). 저장소 자체는 이미 비활성화되었을 수 있습니다.
5. 영향을 받았다면 **Settings › Applications › Authorized OAuth Apps**에서 GitHub CLI의 접근 권한을 취소하고 `gh auth login`로 다시 로그인한 다음 npm 토큰과 `.env` 파일 및 환경의 모든 비밀값을 교체하세요.
6. 오래된 사본이 다시 설치되지 않도록 npm 캐시를 지우세요.

   ```
   npm cache clean --force
   ```
7. 다음에 대비해 Kilobat의 에이전트 네트워크 로그를 기록하면서 에이전트가 실행한 각 설치가 어디에 연결했는지 확인하세요. npm 또는 node가 api.github.com과 통신하는 경우와 직접 시작하지 않은 에이전트 세션을 주의해서 보세요.

   ```
   kilobat agent-log --all
   ```

## 질문

**AI 도구가 사용자를 공격했나요?**

아닙니다. 악성 스크립트가 권한 확인을 끄는 플래그와 자체 지시를 사용해 도구를 직접 시작했습니다. 이 플래그가 있다는 점은 에이전트를 전체 권한으로 무인 실행할 때 주의해야 하는 이유이기도 합니다.

**Kilobat은 왜 GitHub로의 대용량 업로드를 차단하지 않나요?**

코드, 릴리스 및 패키지를 GitHub에 푸시하는 일은 일반적인 작업이며 이를 차단하면 `git push`가 작동하지 않기 때문입니다. 대신 로그에 업로드의 바이트 수와 프로세스가 표시됩니다.

## 출처

- [nrwl/nx 보안 권고 GHSA-cxm3-wv7p-598c: 악성 Nx 버전 및 일부 지원 플러그인이 게시됨](https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c)
- [Nx 블로그: S1ngularity에서 일어난 일, 대응 및 배운 점](https://nx.dev/blog/s1ngularity-postmortem)
- [StepSecurity: 인기 Nx 빌드 시스템 패키지가 데이터 탈취 악성코드에 감염됨](https://www.stepsecurity.io/blog/supply-chain-security-alert-popular-nx-build-system-package-compromised-with-data-stealing-malware)
- [Wiz: s1ngularity 공급망 공격으로 GitHub에서 비밀값 유출](https://www.wiz.io/blog/s1ngularity-supply-chain-attack)
- [Snyk: Nx 악성 패키지에서 AI 코딩 에이전트를 악성코드에 악용](https://snyk.io/blog/weaponizing-ai-coding-agents-for-malware-in-the-nx-malicious-package/)
- [Socket: AI CLI 도구를 악용하는 공급망 공격으로 Nx npm 패키지 감염](https://socket.dev/blog/nx-packages-compromised)

2026년 11월 1일에 확인했습니다.

## 에이전트와 앱이 어디에 연결하는지 확인하세요

Kilobat은 모든 연결 뒤에 있는 앱, 프로세스 및 에이전트의 이름을 표시하고 알려진 악성 호스트를 차단하며 각 에이전트 세션이 연결한 대상을 기록하는 Mac 메뉴 막대 앱입니다.

[Mac용 다운로드 ↓](https://kilobat.app/downloads/Kilobat-1.31.1.dmg?via=site)

```
brew install seifip/kilobat/kilobat
```

## 다른 보안 사고

- [‘Shai-Hulud’ npm 웜](https://kilobat.app/ko/incidents/shai-hulud-npm-worm): 개발자의 토큰을 훔쳐 이를 이용해 자신을 다시 게시하고 GitHub와 webhook.site를 통해 비밀 정보를 유출한 웜입니다.
- [postmark-mcp 백도어](https://kilobat.app/ko/incidents/postmark-mcp): Postmark를 통해 이메일을 보내는 MCP 서버가 모든 메시지에 숨은 참조를 몰래 추가했습니다.
- [모든 보안 사고](https://kilobat.app/ko/incidents): Kilobat이 할 수 있었던 일과 할 수 없었던 일을 담은 모든 사례 연구입니다.
