개발하면서 평소에 쓰는 프레임워크, 패키지 매니저, IDE, 확장 프로그램… 이런 도구들은 안전하다고 믿고 매일 사용하게 됩니다. 하지만 때로는 그 신뢰가 예상치 못한 보안 위험으로 이어질 수 있습니다.
이 글은 IDE의 확장 프로그램을 통해 예기치 않게 공급망 공격을 당한 경험과, 어떻게 원인을 추적하고 대응했는지에 대한 이야기입니다.
예상치 못한 피해 발견
2025년 8월 26일, 전 세계적으로 Nx 패키지 공급망 공격이 발생했습니다.
Nx란? 여러 프로젝트를 하나의 저장소에서 효율적으로 관리할 수 있게 도와주는 모노레포 개발 도구입니다.
Nx 패키지 공급망 공격이란? 2025년 8월 26일, 악의적인 공격자가 npm의 Nx 패키지(21.5.0, 20.9.0 등)에 악성 코드를 삽입해 배포한 사건입니다. 이 악성 버전들은 사용자 시스템의 파일을 스캔하고 GitHub 토큰, 환경변수 등 민감한 정보를 수집해 사용자 계정에 s1ngularity-repository 이름의 악성 레포지토리를 자동으로 생성하여 탈취한 데이터를 외부로 전송했습니다.
하지만 저는 그 사실을 전혀 모르고 있었습니다.
하루가 지난 8월 27일, 보안팀으로부터 예상치 못한 알림을 받게 되었습니다.

하지만 제가 사용하던 Nx 버전이 14.5.1로, Nx 보안 사고의 악성 버전(20.x-21.x)과는 전혀 무관한 안전한 버전이었다는 점입니다.
이상했습니다. 직접적인 Nx 관련 작업도 하지 않았는데 어떻게 감염된 걸까요?
즉각적인 대응
보안팀의 알림을 받고 원인 파악보다는 추가 피해 방지가 우선이었기에 즉시 다음 조치를 취했습니다.
- GitHub Personal Access Token 전체 삭제
- 환경변수 내 민감 정보 점검
- 시스템 전반 추가 감염 여부 확인
피해 범위 확인
며칠 후, GitHub 계정을 자세히 확인해 보니 s1ngularity-repository-1이라는 악성 레포지토리는 이미 GitHub 측에서 선제적으로 삭제한 상태였습니다.
유출된 데이터의 정확한 내용을 파악하기 위해 GitHub Support를 통해 해당 레포지토리의 내용을 확인할 수 있도록 복구를 요청했고, 복구된 레포지토리를 확인해 보니 다음과 같은 정보들이 유출되어 있었습니다.
유출된 정보
- GitHub Personal Access Token
- 전체 환경변수 (NODE_PATH, JAVA_HOME, API 키 등)
- 개발 도구 경로 및 설정
- 시스템 정보 (hostname, OS 정보)
기본적인 정보와 함께 GitHub 토큰이 유출되었으나 개발에는 GitLab만 사용하고 있기에 유출된 토큰의 GitHub 계정에는 아무런 코드도 존재하지 않아서 실질적인 문제는 없었습니다.
최근 npm의 여러 패키지(Nx, eslint-config-prettier, chalk, debug 등)에서 보안 사고가 연이어 발생하고 있습니다. 만약 GitHub에서 악성 레포지토리를 자동 삭제했더라도, GitHub Support에 요청하면 일시적으로 복구하여 피해 범위를 확인할 수 있습니다.
하지만 가장 큰 의문은 남아있었습니다. "어떻게 감염된 걸까?"

출처 : LMArena 생성 이미지
범인 찾기
가설 1. 직접 패키지 설치를 통한 감염?
일단 정말로 안전한 버전을 쓰고 있는지부터 확인해 봤습니다.
$ npm list nx nx-monorepo@0.0.0 /Users/username/.../ ├─┬ @nrwl/cli@14.5.1 │ └── nx@14.5.1 deduped ├─┬ @nrwl/cypress@14.5.1 │ └─┬ @nrwl/devkit@14.5.1 │ └── nx@14.5.1 deduped ├─┬ @nrwl/linter@14.5.1 │ └── nx@14.5.1 deduped ├─┬ @nrwl/workspace@14.5.1 │ └── nx@14.5.1 deduped └─┬ nx@14.5.1 └─┬ @nrwl/tao@14.5.1 └── nx@14.5.1 deduped여러 프로젝트 중 단 한 프로젝트에서만 Nx를 사용하고 있고, 안전한 14.5.1 버전이었습니다.
가설 2. 패키지 매니저 글로벌/캐시를 통한 감염?
직접 설치는 없었으니, 이제 패키지 매니저의 글로벌 영역이나 캐시를 의심해 봤습니다.
$ npm list -g nx /Users/username/.nvm/versions/node/v22.3.0/lib └── (empty) $ yarn global list yarn global v1.22.22 warning package.json: No license field info Found 0 packages. $ ls ~/.npm/_npx # (폴더는 존재하지만 nx 관련 캐시 없음)확인 결과 글로벌 설치 이력은 없었으며, 캐시에서도 유의미한 정보는 없었습니다.
가설 3. IDE 확장 프로그램을 통한 감염?
여기서 문득 생각이 들었습니다. 직접 설치도 없고, 글로벌이나 캐시에서도 흔적을 찾을 수 없다면 다른 경로가 있을까? 그때 확장 프로그램인 Nx Console이 설치되어 있다는 게 떠올랐습니다. 혹시 Nx Console이 패키지를 설치하거나 실행할 수 있지 않을까 하는 생각이 들어서, 제가 사용 중인 커서의 로그를 뒤져보기로 했습니다.
$ grep -r "nxConsole" ~/Library/Application\ Support/Cursor/logs/20250827T110537/그리고 여기서 단서를 발견했습니다.
2025-08-27 11:05:40.033 [info] Added views:nxConsole.views.welcome,nxHelpAndFeedback in workbench.view.extension.nx-console보안사고 시점의 Nx Console 활성화 로그를 확인할 수 있었습니다. 그 다음엔 해당 확장 프로그램의 GitHub 레포지토리에서 관련된 내용을 확인해서 Nx Console이 원인임을 알게 되었습니다.
원인 파악을 위한 다른 접근 방법
당시에는 기기 중심으로 원인을 찾아갔지만, GitHub Security Log에서 악성 레포지토리 생성 시점을 먼저 확인하고 그 시간대를 기반으로 역추적하는 방법도 있었을 것 같습니다. 또는 확장 프로그램이 의심되었다면, 사용 중인 여러 확장 프로그램의 최근 보안 이슈 검색(Nx Console Security)이나 변경 사항 확인(Pull Request #2724, 릴리즈 노트 보안 패치 이력 확인 등) 같은 정보들을 먼저 확인하는 것도 괜찮은 방법이 아니었나 싶어요.
감염 과정
범인을 찾았으니 이제 어떻게 감염이 일어났는지 파헤쳐봤습니다. Nx Console의 GitHub 저장소를 클론해서 실제 코드를 확인해 본 결과 아래와 같았습니다.
저는 커서를 통해 발생했지만, 이번 문제는 Nx Console이라는 VS Code 확장 프로그램이 원인이기에 VS Code뿐만 아니라 Windsurf 등 VS Code 확장 프로그램을 지원하는 모든 에디터에서 동일하게 발생할 수 있습니다.
1. 커서 실행
파일: apps/vscode/package.json
{ "activationEvents": ["onStartupFinished"] }Nx Console은 onStartupFinished 이벤트를 사용하도록 설정되어 있습니다. 그래서 커서를 시작하면 현재 워크스페이스가 Nx 프로젝트가 아니어도 자동으로 활성화되죠.
2. Nx Console 활성화
보안 사고 당시 코드 apps/vscode/src/main.ts
// Run `npx nx@latest --version` once on activation try { const workspacePathForNxVersion = workspace.workspaceFolders && workspace.workspaceFolders[0].uri.fsPath; exec('npx -y nx@latest --version', { cwd: workspacePathForNxVersion, env: { ...process.env }, }); } catch { // ignore errors }Nx Console은 매번 활성화될 때마다 nx의 최신 버전을 가져와서 실행하고 있었습니다.
npx는 패키지를 임시로 다운로드해서 실행하는 도구인데, 문제는 당시 npm에 올라간 최신 버전이 악성 버전이었기에 악성 버전을 실행했다는 점입니다.
따라서, 해당 코드로 인해 활성화와 동시에 자동으로 명령어(npx nx@latest --version)가 실행되었고, 제 컴퓨터는 자연스럽게 감염되었습니다.
3. 악성 패키지의 실제 동작
악성 NX 패키지(21.8.0 등)에는 telemetry.js라는 파일이 포함되어 있었는데, 이 파일이 --version 명령어 실행 시 함께 동작하면서 시스템 정보를 수집했습니다. 단순한 버전 확인 명령어지만 실제로는 데이터 탈취 코드가 실행된 거죠.
실제 감염 과정

Nx Console 감염 과정
- 커서 실행 및 시스템 초기화
- onStartupFinished 이벤트 발생으로 Nx Console 확장 자동 활성화
- Nx Console이 백그라운드에서 npx -y nx@latest --version 실행
- npm 레지스트리에서 악성 nx@21.8.0 패키지 다운로드
- 악성 패키지 내 telemetry.js가 --version 명령어와 함께 실행
- 시스템 스캔을 통한 환경변수, GitHub 토큰 등 민감 정보 수집
- 수집된 데이터로 GitHub에 s1ngularity-repository-1 악성 레포지토리 생성
- 정상적인 버전 정보를 반환하며 평소와 동일한 Nx Console UI 표시
전체 과정은 백그라운드에서 완료되고, Nx Console을 이용한다 해도 정상적인 UI가 표시되기에 사실상 인지가 어려웠던 것이죠.
정말 소름 돋는 건, 감염이 얼마나 은밀한지였습니다.
직접 패키지를 설치하면 "어? 내가 뭘 설치했지?" 하고 기억이라도 날 텐데, 확장 프로그램은 처음에는 생각조차 못했기 때문입니다.
Nx Console의 대응
사건 발생 후 Nx Console 팀은 단계적으로 신속하게 대응했습니다.
1. 위험 제거 (8월 27일)
PR #2718: fix(vscode): remove version check on startup
가장 먼저 활성화 시 자동으로 실행되던 npx nx@latest --version 코드를 완전히 제거하여 실행 시 발생하는 피해를 막는 긴급 조치를 진행하였습니다.
2. 보안 검증 (8월 28일)
PR #2724: fix: always check nx@latest provenance status before executing anything from it
초기 대응 이후 바로 다음 날인 28일, nx 명령어를 실행하기 전에 반드시 provenance를 검증하도록 아래와 같은 변경이 적용되었습니다.
- nx@latest 실행 전 npm registry에서 provenance 상태 확인
- provenance가 검증된 패키지만 실행
- pnpm -y 플래그 오인 문제도 함께 해결
이런 대응을 통해 Nx Console은 앞으로 비슷한 공급망 공격을 사전에 차단할 수 있게 되었습니다.
마무리
개인적으로는 이 사건 이후 커서의 확장 프로그램 자동 업데이트를 비활성화하고, 불필요한 여러 확장 프로그램을 정리했습니다. 이번에는 실행으로 발생했지만, 업데이트를 통해서도 비슷한 일이 생길 수 있고, 다른 확장 프로그램에서도 발생할 가능성도 염두에 두게 되었습니다.
다만 이런 공급망 공격이 신뢰할 수 있는 프로그램에서 발생한 것이다 보니 예방이 어렵다고 생각합니다. 모든 확장프로그램이나 라이브러리를 의심하고 사용을 피할 수는 없으니까요. 그래서 피해 범위를 줄이는 방향으로 접근하게 되었고, 토큰 권한을 최소화하고 정기적으로 갱신하는 방식과 민감한 정보를 최소화하는 형태로 환경변수를 개선했습니다.
마지막으로 개발 편의성과 보안 사이의 균형이 얼마나 중요한지 깨달았습니다. 신뢰할 수 있는 도구라고 해서 무조건 안전한 것은 아니며, 특히 자동화된 기능들에 대해서는 더욱 신중한 접근이 필요하다는 것도요.











English (US) ·