Bitwarden CLI, 진행 중인 Checkmarx 공급망 캠페인에서 손상됨
(socket.dev)- npm용 Bitwarden CLI 패키지가 진행 중인 Checkmarx 공급망 공격의 일부로 손상됐고, 현재 확인된 영향 범위는
@bitwarden/cli2026.4.0 빌드에 한정됨 - 패키지에 포함된
bw1.js악성 코드는audit.checkmarx[.]cx/v1/telemetry같은 동일한 인프라와 난독화 방식을 사용하며, 손상된 GitHub Action을 이용한 CI/CD 침해 정황과도 맞물림 - 수집 대상은 GitHub 토큰뿐 아니라 AWS, Azure, GCP 자격 증명,
.npmrc, SSH 키, 환경 변수, Claude/MCP 설정 파일까지 넓게 퍼져 있음 - 탈취한 정보는 공개 GitHub 저장소 생성과 커밋, npm 토큰을 이용한 재배포 확산, workflow 주입으로 이어지며,
~/.bashrc와~/.zshrc수정 같은 지속성 확보 기능도 포함됨 - Bitwarden CLI를 사용한 조직은 이번 사건을 자격 증명 노출과 CI/CD 침해로 다뤄야 하며, CI 로그 검토와 노출 가능 비밀정보 교체가 중요함
개요
- Bitwarden CLI npm 패키지가 진행 중인 Checkmarx 공급망 공격의 일부로 손상되었고, 확인된 대상 버전은
@bitwarden/cli2026.4.0임- 악성 코드는 패키지에 포함된
bw1.js에 들어 있었음 - 공격 경로는 Bitwarden의 CI/CD 파이프라인 안에서 손상된 GitHub Action을 활용한 정황과 맞물리며, 다른 저장소들에서 확인된 캠페인 패턴과 일치함
- 악성 코드는 패키지에 포함된
- 현재까지 확인된 범위는 Bitwarden CLI 빌드에 한정되어 있고, 손상은 더 넓은 Checkmarx campaign에서 식별된 GitHub Actions 공급망 벡터를 따름
- npm용 CLI 패키지만 관련되어 있음
- Chrome 확장, MCP 서버, 그 밖의 정식 배포물은 현재까지 영향이 확인되지 않았음
- 조사는 계속 진행 중이며, 전체 기술 분석과 영향 버전, 침해 지표, 대응 지침은 추가 공개될 예정임
- Bitwarden CLI를 사용하는 경우 CI 로그 검토와 노출 가능성이 있는 비밀정보 교체가 필요함
기술 분석
- 악성 페이로드
bw1.js는 전날 분석된 Checkmarx의mcpAddon.js와 핵심 인프라를 공유함- 동일한 C2 엔드포인트
audit.checkmarx[.]cx/v1/telemetry를 사용하고,__decodeScrambled와 시드0x3039로 난독화되어 있음 - GitHub API를 통한 커밋 기반 유출과 npm 레지스트리를 통한 토큰 탈취 및 재배포도 함께 수행함
- 동일한 C2 엔드포인트
- 내장된 페이로드 구조도 같은 계열임
- gzip+base64 구조 안에 GitHub Actions
Runner.Worker메모리를 긁어 GitHub 토큰을 노리는 Python 스크립트가 포함됨 - 재배포 npm 패키지를 위한
setup.mjs로더, GitHub Actions workflow YAML, 하드코딩된 RSA 공개키, 이념적 선언문 문자열이 함께 들어 있음
- gzip+base64 구조 안에 GitHub Actions
- 자격 증명 수집 범위가 매우 넓음
- GitHub 토큰은
Runner.Worker메모리 스크래핑과 환경 변수에서 수집함 - AWS 자격 증명은
~/.aws/파일과 환경 변수에서 찾음 - Azure 토큰은
azd를, GCP 자격 증명은gcloud config config-helper를 통해 수집함 .npmrc, SSH 키, 환경 변수, Claude/MCP 설정 파일도 대상에 포함됨
- GitHub 토큰은
- GitHub를 통한 유출 방식도 구체적으로 확인됨
- 피해자 계정 아래에 Dune 테마 이름 규칙
{word}-{word}-{3digits}를 따르는 공개 저장소를 생성함 - 암호화된 결과물을 커밋하고, 커밋 메시지에는
LongLiveTheResistanceAgainstMachines마커와 함께 토큰을 삽입함
- 피해자 계정 아래에 Dune 테마 이름 규칙
- 공급망 확산 메커니즘까지 포함됨
- 탈취한 npm 토큰으로 쓰기 가능한 패키지를 찾아 preinstall hook가 삽입된 상태로 재배포함
- GitHub Actions workflow를 주입해 저장소 비밀정보를 추가로 수집함
- 러시아 로캘 킬 스위치가 존재함
- 시스템 로캘이
"ru"로 시작하면 조용히 종료함 Intl.DateTimeFormat().resolvedOptions().locale와LC_ALL,LC_MESSAGES,LANGUAGE,LANG환경 변수를 확인함
- 시스템 로캘이
- 런타임은 Bun v1.3.13이며 GitHub Releases에서 내려받음
Checkmarx 사고와 다른 지점
bw1.js에는 Checkmarx 사고 문서에 없던 추가 침해 지표가 들어 있음- 하드코딩된 잠금 파일
/tmp/tmp.987654321.lock으로 동시 실행을 막음 ~/.bashrc와~/.zshrc에 페이로드를 주입해 셸 프로필 지속성을 확보함- 저장소 설명을
Shai-Hulud: The Third Coming으로 설정하고, 디버그 문자열에"Would be executing butlerian jihad!"를 포함하는 등 명시적 브랜딩을 사용함
- 하드코딩된 잠금 파일
- 공유 도구가 동일한 악성코드 생태계 연결성을 강하게 시사하지만, 운영 서명은 귀속 판단을 더 어렵게 만듦
- Checkmarx 공격은 발견 뒤 TeamPCP가
@pcpcats소셜 계정을 통해 자신들의 소행이라고 주장했음 - 해당 악성코드는 정상처럼 보이는 설명으로 위장하려 했음
- Checkmarx 공격은 발견 뒤 TeamPCP가
- 이번 페이로드는 공개적 태도가 다름
- Shai-Hulud 저장소 이름,
"Butlerian Jihad"선언문, 기계에 대한 저항을 내세운 커밋 메시지처럼 이념적 표식이 악성코드 안에 직접 들어 있음 - 공유 인프라를 쓰는 다른 운영자, 더 강한 이념성을 가진 분파, 또는 캠페인의 공개적 태도 변화라는 여러 가능성이 함께 남아 있음
- Shai-Hulud 저장소 이름,
권고 사항
- 악성 Bitwarden npm 패키지를 설치한 조직은 이번 사건을 자격 증명 노출과 CI/CD 침해 사건으로 취급해야 함
- 개발자 시스템과 빌드 환경에서 영향 패키지를 즉시 제거하고, 해당 환경에 노출됐을 수 있는 자격 증명을 모두 교체해야 함
- GitHub 토큰, npm 토큰, 클라우드 자격 증명, SSH 키, CI/CD 비밀정보가 포함됨
- GitHub에서는 비인가 저장소 생성과 비정상 workflow를 점검해야 함
.github/workflows/아래의 예상치 못한 파일, 의심스러운 workflow 실행, artifact 다운로드, Dune 테마 이름 패턴{word}-{word}-{3digits}를 따르는 공개 저장소를 확인해야 함- 영향 가능성이 있으면 새로 게시된 저장소에서 아래 키워드를 점검해야 함
atreidescogitorfedaykinfremenfutargesseritgholaharkonnenheighlinerkanlykralizeclasgunlazamelangementatnavigatorornithopterphibianpowindahpranaprescientsandwormsardaukarsayyadinasietchsiridarsligstillsuitthumpertleilaxu
- npm에서는 비인가 배포 여부를 감사해야 함
- 승인되지 않은 publish, 버전 변경, 새로 추가된 설치 훅을 확인해야 함
- 클라우드 환경에서는 접근 로그를 재검토해야 함
- 비정상적인 비밀정보 접근, 토큰 사용, 새로 발급된 자격 증명을 추적할 필요가 있음
- 엔드포인트와 러너에서는 관측된 유출 인프라와 파일 접근 흔적을 추적해야 함
audit[.]checkmarx[.]cx로의 외부 연결을 찾을 필요가 있음- 평소 사용하지 않는 환경에서 Bun 실행이 있었는지 확인해야 함
.npmrc,.git-credentials,.env, 클라우드 자격 증명 저장소,gcloud,az,azd접근 흔적을 살펴봐야 함/tmp/tmp.987654321.lock존재 여부와~/.bashrc,~/.zshrc수정 여부도 확인해야 함
- GitHub Actions에서는 승인되지 않은 workflow 생성 여부를 검토해야 함
- 임시 브랜치에서 workflow가 만들어졌는지 확인이 필요함
format-results.txt같은 artifact가 생성되거나 다운로드되었는지도 점검해야 함
- 장기적으로는 향후 공급망 사고의 피해 반경 축소가 필요함
- 토큰 권한 범위를 줄이고 가능하면 단기 수명 자격 증명을 사용해야 함
- 패키지 생성 및 배포 권한을 제한하고 GitHub Actions 권한을 강화해야 함
- 불필요한 artifact 접근을 비활성화하고, 정상 릴리스 절차 밖에서 생긴 공개 저장소나 workflow 변경을 모니터링해야 함
침해 지표
-
악성 패키지
-
네트워크 지표
94[.]154[.]172[.]43https://audit.checkmarx[.]cx/v1/telemetry
-
파일 시스템 지표
/tmp/tmp.987654321.lock/tmp/_tmp_<Unix Epoch Timestamp>/package-updated.tgz
Hacker News 의견들
-
최소 릴리스 대기 기간을 두는 것보다 더 나은 방어책이 있는지 궁금함
.npmrc에min-release-age=7만 넣었어도, 약 19시간 전 올라왔다가 악성으로 드러난@bitwarden/cli 2026.4.0을 받은 334명은 피할 수 있었을 것 같음
비슷하게axios,ua-parser-js,node-ipc사례에도 꽤 잘 맞고,event-stream처럼 오래 잠복한 경우엔 못 막아도 대부분의 급성 공급망 공격엔 효과가 있어 보임
설정 예시로 npm/pnpm/bun/uv 각각에 대기 시간을 넣는 방법이 있고, 원클릭으로 점검·적용하는 도구가 없어서 직접 https://depsguard.com을 만들었음
비슷한 아이디어의 https://cooldowns.dev도 방금 확인함- Aikido safe-chain을 쓰고 있음
최소 릴리스 대기 기간만 거는 게 아니라, npm/uv 등을 감싸는 래퍼로 설치 전에 각 의존성을 상용 취약점 데이터베이스와 대조해 알려진 문제나 의심 신호를 검사해 줌 - 쿨다운 아이디어는 좋은데, 아무도 바로 업데이트하지 않았다면 이 공격이 과연 잡혔을지도 궁금함
현실에선 늘 누군가는 즉시 업데이트하겠지만, 이런 사고가 드러나는 과정 자체가 빠른 업데이트 사용자들에 기대는 면이 있어 보임 - backend나 CLI 도구를 NPM에 두지 않는 것부터 시작하는 편이 낫다고 봄
- 새로 설치할 때는 그렇다 쳐도, 기존 의존성은 patch 버전으로 pin하고 sha를 고정하면 되지 않나 싶음
- 이런 공격은 대개 upstream source까지 들어가지 않아서, https://www.chainguard.dev/libraries처럼 소스에서 빌드하는 방식이면 대략 98%는 막을 수 있음
레지스트리 바이너리를 그대로 당겨와야 한다면 쿨다운으로 위험을 조금 낮출 수 있음
GitHub 쪽까지 침투한 긴 꼬리 사례는 커밋·메인테이너 휴리스틱과 AI 기반 코드 변경 분석을 돌리고, 이상 징후가 있으면 사람이 검토하는 조합이 필요해 보임
참고로 여기서 일하고 있음
- Aikido safe-chain을 쓰고 있음
-
이번 사고는 빌드 파이프라인이 탈취돼서 오염된 패키지가 배포된 게 핵심임
그래도 업무상 중요한 걸 npm에 얹고 있다면 의존성은 꼭 pinning하는 편이 낫다고 봄
많은 개발자가 lockfile이면 충분하다고 여기지만,^범위가 남아 있으면 lockfile 갱신 시 내가 명시적으로 고르지 않은 새 버전을 끌어올 수 있음
회사 존립에 영향 줄 수 있는 시스템이라면 이 정도 번거로움은 감수할 가치가 있음- 반대로 생각하면, 나중 버전에서 보안 취약점이 수정됐을 때는 시스템이 그걸 자동으로 받아 적용해 주는 게 이상적이기도 함
-
https://github.com/doy/rbw는 Bitwarden CLI의 Rust 대안임
Rust 생태계도 점점 npm처럼 크고 깊은 의존성 트리로 가는 느낌이 있지만, 그래도 JavaScript에서 흔한 경우보다 신뢰해야 할 작성자 수는 훨씬 적은 편임- https://github.com/doy/rbw/blob/main/Cargo.toml#L16를 보면 여기도 의존성은 꽤 많음
그래도 적어도 버전은 pin되어 있음 - Firefox 내장 비밀번호 관리자를 쓰는 데 단점이 있는지 궁금함
- 다들 Rust를 더 안전하다고 보면서도, 의존성을 통해 멀웨어를 끌어올 위험이 크게 늘어난 건 너무 쉽게 무시하는 듯함
rbw + vaultwarden조합이면 self-hostable Rust 버전의 Bitwarden처럼 굴러가서 꽤 괜찮음- 이런 일 때문에 더 많은 소프트웨어가 .Net처럼 서드파티 의존성 없이도 대부분 해결되는 스택으로 갈 수도 있겠다고 봄
반대로 언어 표준 라이브러리에 기능을 더 많이 넣는 쪽으로 갈 수도 있음
- https://github.com/doy/rbw/blob/main/Cargo.toml#L16를 보면 여기도 의존성은 꽤 많음
-
Bitwarden CLI 경험이 아주 나빴음
bw list를 실행했더니 비밀번호 이름만 나올 줄 알았는데, 실제로는 비밀번호와 현재 TOTP 코드까지 전부 보여줬음
더 무서운 건 서버에 ssh로 들어가 tmux 안의 weechat를 열어 보니,bw명령의 전체 내용이 weechat 입력 히스토리에서 접근 가능했다는 것임
왜 그런지 전혀 모르겠고, tmux와 weechat 세션을 넘어 계속 남아 있었고 서버를 재부팅해야만 사라졌음
그 뒤로bwCLI는 바로 지웠고 다시 설치할 생각도 없음
참고로 터미널은 ghostty를 씀- 이건 본 주제와 상관없는 불평에 가까움
- CLI를 써보려다가 JavaScript 기반인 걸 보고 접었음
- 정말 이상한 일임
weechat에bwcli확장이라도 있는 건지 궁금하고, Bitwarden에 CLI가 있는지도 이번에 처음 알았음
나는 로컬에서 keepass를 씀
-
CLI는 안 써봤지만 브라우저 플러그인은 쓰고 있음
이게 뚫리면 정말 큰일인데, 뭘 해야 막을 수 있을지 모르겠음
검증된 구버전을 계속 쓰는 게 답인지 고민됨
내 삶의 상당 부분이 이 비밀들이 비밀로 남는 데 달려 있다는 사실이 새삼 기묘하게 느껴짐- 통합 지점이 많아질수록 공격면도 커짐
그래서 비밀번호 관리자 브라우저 확장은 아예 쓰지 않음
예전에 브라우저 연동에서 보안 문제가 있었던 제품을 본 뒤로 완전히 피하게 됐고, iOS 통합은 상대적으로 더 믿지만 그래도 경계함 - 쿨다운은 기본값으로 어디에나 들어가야 한다고 봄
개발용 패키지 매니저, OS 패키지 매니저, 브라우저 확장, 독립 앱의 자동 업데이트까지 전부 포함해서 말임
Socket 같은 회사가 악성 업데이트를 잡아낼 시간을 벌어야 하는데, 모두가 게시 몇 분 만에 내려받으면 그런 탐지 자체가 무의미해짐 - 내 디지털 자산 중 가장 소중한 이메일과 Bitwarden 계정은 항상 몸에 지니는 Yubikey 하나와 다른 지역에 둔 백업 키 하나로 보호하고 있음
이런 구성을 강력히 추천함
제목 보고 좀 식겁하긴 했지만, 편집증으로 갈 정도는 아니면서 합리적으로 할 수 있는 건 다 하고 있다고 느낌 - 브라우저 플러그인 대신 데스크톱 앱이나 웹 vault를 직접 쓰면 됨
- 막는 방법은 간단히 말해 이 둘임
https://cooldowns.dev
https://depsguard.com
두 번째 건 내가 관리하고 있고, 첫 번째를 미리 알았으면 굳이 만들지 않았을 듯함
둘 다 거의 같은 일을 하고, 내 쪽은 Rust를 써서 약간 과한 편임
- 통합 지점이 많아질수록 공격면도 커짐
-
여기서 가장 중요한 건 npm install만으로 충분했다는 사실임
침해 지점이preinstall이면, 설치 후 검사하자는 통념은 바로 무너짐
그 시점엔 이미 페이로드가 실행될 기회를 얻었기 때문임
이건 에이전트, CI, ephemeral sandbox 환경에서 더 흥미로운데, 노출 시간이 짧아도 설치가 자동으로 반복되면 충분히 당할 수 있음
또 하나 주목할 건 이 페이로드가 비밀정보만 노린 게 아니라 AI 툴링 설정도 겨냥했다는 점임
셸 프로필 변조가 다음 코딩 어시스턴트가 읽어갈 컨텍스트를 오염시키는 경로가 될 가능성도 꽤 현실적임
이 관점은 AgentSH 작업과 함께 https://www.canyonroad.ai/blog/the-install-was-the-attack/에 더 길게 적어둠- 설치 후 패키지를 검사하는 사람은 사실상 없고, npm install 스크립트만 특별히 문제 삼는 건 여러 번 반박된 주장이라고 봄
어차피 결국 실제 바이너리를 실행하게 됨
그리고 정말 따지자면 설치 전에 패키지를 직접 받아 검사할 수도 있는데, 설치 프로그램의 동작 보장과 범위를 깊이 이해하지 못한다면 악성 코드를 내려받고 풀어놓는 과정을 어설프게 신뢰하는 쪽이 더 이상함
- 설치 후 패키지를 검사하는 사람은 사실상 없고, npm install 스크립트만 특별히 문제 삼는 건 여러 번 반박된 주장이라고 봄
-
러시아 로캘 kill switch라니, 대담하면서도 비겁해 보임
- 더 나쁜 건 이게 진짜 흔적인지, 아니면 false flag인지조차 알 수 없다는 점임
Discretion is the better part of valor같은 온갖 격언이 다 떠오름
요컨대 자기 발등은 찍지 않는다는 태도처럼 보임- 그 자체로 결정적 증거는 아님
Vault7유출에서도 NSA와 CIA가 출처를 흐리려고 이런 흔적을 일부러 남긴다는 내용이 있었고, 다른 국가 행위자들도 충분히 쓸 법한 기법임 - 다른 나라가 건 협박성 공작처럼도 보임
- npm publish GitHub CI 작업에서 누가 로캘을 그렇게 맞춰 두겠냐 싶음
너무 노골적인 오도용 흔적 같지만, 동시에 국가 행위자가 개입했다는 인상을 강하게 주긴 함
-
KeePass 사용자로 살면 이런 스트레스가 훨씬 적음
지난 5년만 해도 로컬 인프라에 KeePass를 써서 여러 보안 사고를 피했음- 이번 건 vault 자체가 아니라 접근 도구가 문제였음
KeePass용 접근 도구라고 해서 이런 문제가 불가능한 건 아닌데, 무엇이 다르다는 건지 잘 모르겠음 - 비밀번호를 인프라와 휴대폰에서 함께 접근해야 하는데, KeePass로 그걸 어떻게 해결하는지 궁금함
불가능하다고 생각해 왔지만 솔직히 깊게 파보진 않았음 - 자기 인프라를 굴릴 수 있는 사람에겐 좋겠지만, stress free라는 표현을 평균 사용자에게까지 적용하긴 어려움
- 단일 파일 방식은 알겠는데, 현실적으로 동기화와 충돌 해결을 어떻게 하는지 궁금함
두 기기가 오프라인 상태에서 각각 비밀번호를 추가한 뒤 다시 온라인이 되면 어떻게 처리하나 싶음 - KeePass에서 아직 감을 못 잡은 건 클라우드 백업임
백업을 암호화하면 그 암호는 어디에 저장하고, 또 클라우드 제공자 비밀번호는 어디에 저장해야 하나 싶음
- 이번 건 vault 자체가 아니라 접근 도구가 문제였음
-
이번 공격에서 특히 인상적인 건, 공격자들이 GitHub가 다운되지 않은 타이밍과 정확히 맞춰야 했다는 점임
- GitHub는 최근에 가동 시간 이슈가 좀 있었음
https://mrshu.github.io/github-statuses/
- GitHub는 최근에 가동 시간 이슈가 좀 있었음
-
그래서 나는 서드파티 비밀번호 관리자를 아예 쓰지 않음
보안, 업데이트, 백업 같은 걸 제대로 해줄 거라고 계속 믿어야 하기 때문임
직접 stateless 비밀번호 생성기를 만들었고, 덕분에 기기 간 데이터 백업이나 동기화가 아예 필요 없음
아주 길고 강한 마스터 비밀번호와 서비스명, 사용자명을 넣으면 적절한 파라미터의 scrypt 해시를 돌려 브루트포스를 사실상 불가능하게 만드는 방식임
중요한 계정엔 2FA도 함께 씀