Back to all posts
Cybersecurity

11분의 악몽: Nx Console VS Code 확장 프로그램 침해의 내막

로컬 코딩 환경이 안전한 샌드박스라고 생각한다면 믿을 수 없을 정도로 나쁜 소식이 있습니다. 2026년 5월 18일, 개발자 커뮤니티는 잔혹한 보안 충격으로 잠에서 깨어났습니다. 220만 건 이상 설치된 도구인 Visual Studio Code용 Nx Console 확장 프로그램이 정교한 공급망 공격으로 탈취되었습니다.

TeamPCP로 추적되는 위협 그룹이 Visual Studio Marketplace 및 Open VSX Registry 모두에 오염된 업데이트(v18.95.0)를 성공적으로 게시했습니다. Nx의 유지 관리자는 눈부신 속도로 조치를 취하여 VS Marketplace에서는 11분, Open VSX에서는 36분 만에 확장 프로그램을 제거하고 패치했지만 이미 피해는 발생한 후였습니다. 한 GitHub 엔지니어의 워크스테이션이 자동으로 잘못된 업데이트를 가져왔고, 이로 인해 공격자가 약 3,800개의 내부 GitHub 리포지토리에 침투하여 데이터를 빼낼 수 있는 발판이 마련되었습니다.

저는 지난 이틀 동안 익스플로잇 벡터를 분석했습니다. 이것이 어떻게 발생했는지 분석하고, "고아 커밋(Orphan Commit)" 로더를 재구성하고, 로컬 AI 개발자 키가 새로운 고가치 목표가 된 이유를 살펴보고, 로컬 설정을 잠그기 위해 제가 권장하는 구체적인 전략에 대해 논의해 보겠습니다.


침해 체인 해체

현실을 직시합시다. 이것은 단순한 타이포스쿼팅(typosquatting)이나 종속성 혼동 공격이 아니었습니다. 악의적인 행위자들은 공식 릴리스 파이프라인 자체를 손상시켰습니다.

초기 침해는 Nx 리포지토리에서 시작된 것이 아닙니다. 대신 계단식(cascading) 체인이었습니다. TeamPCP는 이전에 TanStack 생태계의 기여자들을 침해했습니다. 그 진입점을 통해 공식 nrwl/nx 리포지토리에 대한 쓰기 권한을 가진 개발자의 GitHub CLI OAuth 토큰을 빼냈습니다.

가시성이 높은 Pull Request를 열거나 main 에 직접 푸시(브랜치 보호 경보를 트리거함)하는 대신 TeamPCP는 기발하고 은밀한 벡터인 **고아 커밋(The Orphan Commit)**을 사용했습니다.

                           [ TanStack 생태계 침해 ]
                                        │
                         (GitHub OAuth 토큰 유출)
                                        │
                                        ▼
                   [ nrwl/nx 리포지토리에 대한 쓰기 권한 악용 ]
                                        │
              (Git 트리에 직접 생성된 은밀한 고아 커밋)
                                        │
                                        ▼
           [ 악의적인 Nx Console VS Code 확장 프로그램 (v18.95.0) ]
             (고아 커밋을 가져오는 정적 URL로 사전 컴파일됨)
                                        │
                                        ▼
             [ Visual Studio Marketplace / Open VSX 게시됨 ]
                                        │
                                        ▼
                 [ 개발자 머신 자동 업데이트 / 실행 ]

고아 커밋(Orphan Commit)이란 무엇인가?

고아 커밋은 명명된 브랜치, 태그 또는 활성 참조 트리에 연결되지 않은, 리포지토리의 객체 저장소(object store)로 직접 푸시된 커밋입니다.

Git은 콘텐츠 주소 지정이 가능(content-addressable)하기 때문에 저수준 플러밍(plumbing) 명령을 사용하여 커밋을 만들고 푸시할 수 있습니다. main 브랜치 커밋 기록이나 활성 브랜치 목록에는 표시되지 않지만, 커밋은 리포지토리의 객체 저장소에 활성 상태로 남아 있습니다. 정확한 커밋 SHA를 아는 사람은 누구나 코드에 액세스하거나 GitHub의 원시 CDN에서 직접 가져올 수 있습니다.

# Git에서 느슨한 객체(loose objects) 쿼리: 커밋이 고립되더라도,
# 저장되어 있으며 GitHub raw에서 직접 쿼리하거나 가져올 수 있습니다.
git cat-file -p <orphan_commit_sha>

TeamPCP는 간단한 로더로 악성 확장 프로그램을 구축했습니다. 설치가 완료되면 공식 nrwl/nx 리포지토리에 연락하여 숨겨진 이 고아 커밋에서 보조 페이로드를 가져왔습니다. 정적 분석 도구 및 방화벽에서 볼 때 네트워크 요청은 완전히 무해해 보였습니다. 공식 Microsoft VS Code 확장 프로그램이 공식적으로 확인된 리포지토리에서 코드를 가져오고 있었기 때문입니다.

메모리에 로드되면 2차 페이로드가 실행되어 로컬 자격 증명 수집기(credential harvester)가 즉시 가동되었습니다.


AI API 비밀 잠그기

전통적으로 개발자 자격 증명 절도범들은 AWS 액세스 키, NPM 게시 토큰, SSH 키 및 데이터베이스 자격 증명이 포함된 .env 구성과 같은 표준 환경 변수를 찾습니다.

그러나 TeamPCP의 v18.95.0 페이로드에 대한 제 보안 분석 결과, AI 개발자 어시스턴트 자격 증명의 자동화된 수집이라는 뚜렷한 현대적 전환이 밝혀졌습니다.

이 맬웨어는 로컬 구성 경로에서 다음과 같은 활성 터미널 기반 및 IDE 기반 AI 에이전트를 특별히 검색했습니다.

  • ~/.config/claude-code/config.json (API 키 및 세션 토큰이 포함된 Claude Code 구성 파일)
  • ~/.config/github-copilot/
  • ~/.gemini/ API 구성 및 키
  • VS Code Copilot 토큰이 포함된 IDE 보안 스토리지 폴더

AI 키가 새로운 프리미엄 타겟인 이유

이유는 다음과 같습니다. 소프트웨어 엔지니어링이 에이전트 기반 환경을 채택함에 따라 개발자는 터미널 세션 내에서 직접 Claude Code와 같은 높은 권한의 AI 유틸리티를 일상적으로 실행합니다. 이러한 도구에는 파일 작성, 테스트 실행 및 터미널 명령 실행 권한이 부여되는 경우가 많습니다.

공격자가 AWS 키를 훔치면 클라우드 컴퓨팅 액세스 권한을 얻습니다. 공격자가 사용 중인 Claude Code 세션 키를 훔치면 리포지토리의 대화형 에이전트 기반 콘솔을 얻게 됩니다. 에이전트에게 전체 비공개 코드베이스를 읽고, 논리적 결함을 찾고, 조용한 백도어를 작성하고, 풀 리퀘스트를 제출하고, 사용자 이름으로 변경 사항을 커밋하도록 지시할 수 있습니다.

위협 행위자에게 활성화된 AI 개발자 토큰은 궁극적인 피벗 키(pivot key)입니다.


안전한 방어 작업 공간 구축

최신 개발 작업 공간을 보호하려면 IDE가 안전한 샌드박스라는 가정에서 벗어나야 합니다. 머신을 보호하기 위한 제 실용적인 플레이북은 다음과 같습니다.

작업 공간 Dev Container 강제 적용:

개발자는 로컬 머신을 신뢰할 수 없는 환경으로 취급해야 합니다. 호스트 머신의 환경 변수에 대한 전체 액세스 권한을 가진 IDE를 실행하는 대신 Dev Container 또는 컨테이너화된 실행 루프를 사용하십시오.

devcontainer.json 구성으로 환경을 래핑하면 실제 비밀 키를 분리할 수 있습니다.

// devcontainer.json (나의 표준 보안 컨테이너 설정)
{
  "name": "Secure Node Workspace",
  "image": "mcr.microsoft.com/devcontainers/javascript-node:20",
  "features": {
    "ghcr.io/devcontainers/features/common-utils:2": {}
  },
  "containerEnv": {
    "AWS_ACCESS_KEY_ID": "${localEnv:AWS_ACCESS_KEY_ID}" // 로컬 자격 증명은 마스킹된 상태로 유지
  },
  "customizations": {
    "vscode": {
      "settings": {
        "extensions.autoUpdate": false // 내 모르게 확장 프로그램이 자동으로 업데이트되는 것을 방지
      }
    }
  }
}

전문가 팁: 비욘세 규칙 활성화 유지

개발자 자격 증명에 대한 비욘세 규칙이 여기에 적용됩니다. 마음에 들었다면 자물쇠를 채웠어야 했습니다. 자동화된 시스템에 범용 개인 액세스 토큰(PAT)을 절대 사용하지 마십시오. 패키지 메타데이터에 대한 읽기 전용 권한을 가지고 특정 리포지토리로 제한된 세분화된 토큰(fine-grained tokens)을 구현하십시오.


결론

코드 생성은 공식적으로 해결된 문제가 되었으며, 진정한 엔지니어링 전쟁터는 이제 **자격 증명 오케스트레이션 및 격리(containment)**입니다. IDE 확장 프로그램이 무조건 자동 업데이트되도록 내버려두는 것을 멈추고, 작업 공간을 컨테이너에 분리하고, 로컬 AI 구성을 보호하십시오.


참조 및 공식 출처