공지사항

Security Insights & Trends

TensorLake 악성 릴리즈 npm 공급망 공격 - 설치 한 번에 자격증명 위협까지

Raoul16 2026. 10. 14. 12:00

 

TensorLake 악성 릴리즈 npm 공급망 공격 - 설치 한 번에 자격증명 위협까지

 

안녕하세요,

그로메트릭 입니다. 🐸

 

npm install 한 줄이면 끝나는 패키지 설치가, 개발자의 열쇠 꾸러미를 통째로 넘기는 순간이 될 수 있습니다. 개발 환경에 저장된 자격증명이 노출되면 소스 코드 저장소와 빌드·배포 인프라 운영 전반으로 위험이 번질 수 있다는 점에서, 이는 개발자 한 사람의 문제로 끝나지 않습니다.

 

소나타입 리서치팀이 분석한 TensorLake TypeScript SDK의 악성 릴리스(tensorlake@0.5.144)는 설치 시점에 preinstall 훅으로 난독화된 JavaScript 페이로드를 실행했고, GitHub 토큰과 HashiCorp Vault 자격증명은 물론 Claude, Cursor, Kiro, Codex, Gemini, Windsurf 등 AI 개발 도구의 설정·인증 파일까지 찾아 원격 인프라로 전송하도록 설계되어 있었습니다. 여기에 운영자가 보낸 JavaScript를 실행하는 원격 명령 채널, 수집 데이터를 공개 GitHub 저장소에 올릴 수 있는 폴백 경로, 접근 가능한 저장소에 .claude·.vscode 파일을 커밋하는 기능까지 갖추고 있었습니다. 패키지를 삭제해도 이미 읽힌 자격증명은 회수되지 않으며, 토큰을 폐기하기 전에는 토큰 모니터 구성요소 존재 여부를 먼저 확인해야 한다는 점도 짚습니다.

 

이번 글에서는 악성 코드의 동작 방식, CI 환경 확인 로직, 확인된 사실과 미확인 영향, 영향받은 팀의 우선 조치를 정리합니다.

 

*아래 글은 소나타입(Sonatype)의 공식 블로그 글을 번역하여 작성되었습니다.

 


 

탈취된 TensorLake npm 릴리스로 인해 설치가 자격 증명 위험으로 변질되다

요약

  • TensorLake TypeScript SDK의 악성 릴리스 tensorlake@0.5.144는 설치 훅(install hook)을 이용해 개발자 자격증명을 찾고 원격 명령을 받았습니다.
  • 소나타입의 코드 리뷰 결과, 이 악성코드의 GitHub 폴백(fallback)은 공개 저장소를 생성해 수집한 데이터를 커밋할 수 있었으며, 한 경로에서는 탈취한 GitHub 토큰까지 포함됩니다. 또한 접근 가능한 저장소에 .claude, .vscode 파일을 커밋해 저장소를 수정할 수 있습니다.
  • 로더(loader)는 여러 일반적인 CI 환경 표식이 있으면 종료됩니다. 따라서 페이로드에 별도로 들어 있는 GitHub Actions 로직만으로 CI의 광범위한 감염이 입증되지는 않습니다.
  • 탈취된 데이터가 공개되었는지, 저장소가 수정되었는지, 하위(downstream) 시스템이 영향을 받았는지는 아직 확인하지 못했습니다. 해당 릴리스를 설치한 경우에는 훅이 실행되었는지 확인하고, 호스트와 접근 가능한 GitHub 저장소를 조사하며, 해당 프로세스가 사용할 수 있던 자격증명을 검토해야 합니다.

 

악성 설치 훅(Install Hook)이 페이로드를 실행하는 방식 🔄

영향받은 npm 릴리스에는 Bun을 통해 난독화된 JavaScript 페이로드를 시작하는 preinstall 훅이 포함되어 있었습니다. Bun이 없는 경우 패키지는 Bun 1.3.13을 내려받을 수 있습니다.

TensorLake TypeScript SDK의 공식 용도는 샌드박스, 저장소, 클라우드 서비스와 연동하는 것입니다. 자격증명 수집과 원격 명령 실행은 이러한 기능과 무관합니다.

페이로드는 로컬에서 GitHub 토큰과 HashiCorp Vault 자격증명을 비롯한 시크릿을 검색하고, 수집한 데이터를 원격 인프라로 전송합니다. 수집 목록은 AI 개발 도구와 관련된 파일도 노립니다. 구체적으로 Claude, Cursor, Kiro의 MCP 설정, Codex 인증, Gemini OAuth 자격증명, Windsurf 인증 및 설정이 해당합니다.

또한 명령 채널을 주기적으로 확인하고 운영자가 제공한 JavaScript를 평가합니다. 소나타입 리서치 랩(Sonatype Research Labs)은 코드에서 수집 데이터를 게시할 수도 있는 GitHub 기반 폴백도 확인했습니다.

 

GitHub Fallback이 수집 데이터를 공개 저장소에 노출할 수 있다 ⚠️

Socket의 초기 분석은 GitHub를 대체 C2(명령 제어) 경로로 설명합니다.

소나타입 리서치 랩도 코드에서 같은 동작을 확인했으며, 이 폴백에는 또 다른 기능이 있다는 점을 발견했습니다. 폴백이 활성화되면 코드가 private: false를 설정해 공개 GitHub 저장소를 만들고, results/ 아래에 수집한 데이터를 커밋할 수 있습니다.

이 GitHub 폴백 경로에서 수집된 GitHub 토큰에 repository 범위 권한이 있고 Gists API 요청이 빈 목록을 반환하면, 코드는 업로드 데이터와 커밋 메시지에 해당 토큰을 포함시킵니다. 저장소 생성과 커밋이 성공하면 그 토큰이 공개적으로 접근 가능해질 수 있습니다.

 

토큰 접근 권한이 저장소 변조로 이어질 수 있다

웜(worm)형 악성코드는 침해된 개발자 환경 하나를 다른 환경으로 향하는 경로로 바꿀 수 있습니다. 자기복제하는 악성코드가 개발자의 자격증명을 탈취하면, 공통 플랫폼이나 도구를 통해 추가 팀으로 번지면서 공격 표면이 크게 넓어집니다.

이번 사건에서는 코드의 저장소 수정 로직으로 인한 하위 시스템으로의 확산 가능성을 조사하는 것이 중요합니다. 다만 하위로의 확산은 확인하지 못했습니다.

코드에는 실행 컨텍스트와 연결된 저장소를 수정하는 명시적인 로직도 있어, 적격 브랜치 전반에 .claude, .vscode 설정 파일을 커밋할 수 있습니다. 이는 다른 개발자가 해당 저장소를 사용할 때, 도구가 이 파일들을 어떻게 불러오고 실행하는지에 따라 페이로드에 노출되는 결과로 이어질 수 있습니다.
아래 코드는 GitHub 저장소의 구성 정보를 담고 있으며, 저장소를 공개적으로 접근할 수 있도록 하는 설정도 포함되어 있습니다.

 

CI 환경을 확인한 뒤 페이로드를 실행하는 Install Hook ▶️

패키지의 setup.mjs는 페이로드를 실행하기 전에 여러 환경 변수를 확인합니다. CI가 정확히 true 또는 1일 때, GITHUB_ACTIONS 또는 GITLAB_CI가 true일 때, RUNNER_ENVIRONMENT가 github-hosted일 때 종료됩니다. 이는 해당 표식이 있으면 설치 훅이 그 환경을 건너뛴다는 점을 확인해 줍니다. 하지만 코드가 왜 이런 확인을 하는지, 또는 CI 시스템이 캠페인의 의도된 범위 밖이었는지는 입증하지 않습니다.

한 가지 가능성은 자격증명, AI 도구 설정, 지속성 확보 기회를 찾을 수 있는 개발자 워크스테이션에 훅이 집중했다는 것입니다. 이 설명은 그럴듯하지만 추론에 불과합니다. 코드의 동작만으로는 공격자의 의도를 입증할 수 없습니다.

페이로드에는 GitHub Actions 및 저장소 수정 로직도 들어 있습니다. 하나의 가설은 이 로직이 setup.mjs를 우회하는, 심어 둔 워크플로를 통한 직접 실행 같은 또 다른 실행 경로가 될 수 있다는 것입니다. 소나타입은 이 연관성을 입증하지 못했습니다. 코드에 다른 변종에서 물려받았거나 일관되지 않은 로직이 있을 가능성도 있습니다.

확인된 결과는 로더가 해당 CI 마커을 검사하는 부분에만 한정됩니다. CI의 광범위한 감염은 확인하지 못했지만, 건너뛰는 동작만으로는 CI 시스템이 캠페인의 의도된 표적에서 제외되었다고 단정할 수 없습니다.

패키지 고유의 상관관계 단서: WORMTAG

페이로드는 globalThis.WORMTAG를 "tensrlake"로 설정합니다. 연구자는 이 정확한 문자열로 관련 샘플과 활동을 검색할 수 있습니다.
이는 상관관계 파악에 도움이 되지만, 이것만으로 다른 사건이 관련되어 있다고 확정할 수는 없습니다.


영향받은 팀이 가장 먼저 해야 할 조치 ✅

tensorlake@0.5.144를 설치한 경우, 검토가 끝날 때까지 해당 환경에서 사용할 수 있던 자격증명은 노출되었을 가능성이 있는 것으로 취급해야 합니다. manifests, lockfiles, 패키지 캐시, 빌드 기록에서 영향받은 버전을 확인한 뒤 preinstall 훅이 실행되었는지 판단합니다. 훅이 실행된 호스트와 개발·빌드 환경을 조사하십시오.

자격증명을 교체(rotate)하기 전에, 보고된 토큰 모니터 구성요소가 있는지 확인합니다. 공개 분석은 이 모니터가 활성화된 상태에서 탈취된 GitHub 토큰을 폐기(revoke)하면 파괴적 동작이 촉발될 수 있다고 경고합니다. 구성요소가 있다면, 해당 토큰을 폐기하기 전에 지속성 메커니즘을 제거하거나 비활성화한 다음, 프로세스가 접근할 수 있던 자격증명을 교체합니다.

GitHub 감사 활동에서 예상치 못한 접근, 저장소 생성, 브랜치 전반의 커밋을 검토합니다. .claude, .vscode, results/ 경로를 점검하고, 해당 기간에 생성된 공개 저장소가 있는지 확인합니다. HashiCorp Vault 감사 로그에서 예상치 못한 자격증명 접근이 있었는지도 검토합니다. 조사가 끝나면 깨끗한 환경에서 다시 빌드합니다.

패키지를 제거해도 그것이 읽었을 수 있는 자격증명이 폐기되는 것은 아닙니다. 마찬가지로 npm이 릴리스를 삭제해도 이미 설치된 사본이 사라지거나 페이로드가 실행되었는지가 판단되지는 않습니다.

 

행동은 조사하고, 영향을 확인하십시오 📋

TensorLake 릴리스는 설치 시점의 동작도 패키지가 내세우는 기능과 같은 수준으로 면밀히 살펴봐야 하는 이유를 보여줍니다. 이 코드는 자격증명을 수집하고, 원격 명령을 받고, 공개 GitHub 저장소를 통해 수집한 데이터를 게시하고, 탈취한 토큰으로 접근할 수 있는 저장소를 수정할 수 있었습니다.

이러한 능력 때문에 이번 릴리스는 심각하지만, 그것이 데이터가 게시되었거나 하위 저장소가 침해되었음을 입증하는 것은 아닙니다.
tensorlake@0.5.144를 설치한 팀은 훅이 실행되었는지 확인하고, 관련 호스트와 GitHub 활동을 점검하며, 조사 결과에 따라 노출된 자격증명에 대응해야 합니다.

소나타입 리서치 랩은 TensorLake 침해를 계속 조사하고 있으며, 추가 구성요소, 침해 지표(indicator), 영향이 확인되는 대로 sonatype-2026-009038을 업데이트할 예정입니다.

 


출처

소나타입 블로그 : A Hijacked TensorLake npm Release Turned Installation Into a Credential Risk