1P by GN⁺ 14시간전 | ★ favorite | 댓글 1개
  • npm용 Bitwarden CLI 패키지가 진행 중인 Checkmarx 공급망 공격의 일부로 손상됐고, 현재 확인된 영향 범위는 @bitwarden/cli 2026.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 레지스트리를 통한 토큰 탈취 및 재배포도 함께 수행함
  • 내장된 페이로드 구조도 같은 계열임
    • gzip+base64 구조 안에 GitHub Actions Runner.Worker 메모리를 긁어 GitHub 토큰을 노리는 Python 스크립트가 포함됨
    • 재배포 npm 패키지를 위한 setup.mjs 로더, GitHub Actions workflow YAML, 하드코딩된 RSA 공개키, 이념적 선언문 문자열이 함께 들어 있음
  • 자격 증명 수집 범위가 매우 넓음
    • GitHub 토큰은 Runner.Worker 메모리 스크래핑과 환경 변수에서 수집함
    • AWS 자격 증명은 ~/.aws/ 파일과 환경 변수에서 찾음
    • Azure 토큰은 azd를, GCP 자격 증명은 gcloud config config-helper를 통해 수집함
    • .npmrc, SSH 키, 환경 변수, Claude/MCP 설정 파일도 대상에 포함됨
  • GitHub를 통한 유출 방식도 구체적으로 확인됨
    • 피해자 계정 아래에 Dune 테마 이름 규칙 {word}-{word}-{3digits} 를 따르는 공개 저장소를 생성함
    • 암호화된 결과물을 커밋하고, 커밋 메시지에는 LongLiveTheResistanceAgainstMachines 마커와 함께 토큰을 삽입함
  • 공급망 확산 메커니즘까지 포함됨
    • 탈취한 npm 토큰으로 쓰기 가능한 패키지를 찾아 preinstall hook가 삽입된 상태로 재배포함
    • GitHub Actions workflow를 주입해 저장소 비밀정보를 추가로 수집함
  • 러시아 로캘 킬 스위치가 존재함
    • 시스템 로캘이 "ru"로 시작하면 조용히 종료함
    • Intl.DateTimeFormat().resolvedOptions().localeLC_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 소셜 계정을 통해 자신들의 소행이라고 주장했음
    • 해당 악성코드는 정상처럼 보이는 설명으로 위장하려 했음
  • 이번 페이로드는 공개적 태도가 다름
    • Shai-Hulud 저장소 이름, "Butlerian Jihad" 선언문, 기계에 대한 저항을 내세운 커밋 메시지처럼 이념적 표식이 악성코드 안에 직접 들어 있음
    • 공유 인프라를 쓰는 다른 운영자, 더 강한 이념성을 가진 분파, 또는 캠페인의 공개적 태도 변화라는 여러 가능성이 함께 남아 있음

권고 사항

  • 악성 Bitwarden npm 패키지를 설치한 조직은 이번 사건을 자격 증명 노출CI/CD 침해 사건으로 취급해야 함
  • 개발자 시스템과 빌드 환경에서 영향 패키지를 즉시 제거하고, 해당 환경에 노출됐을 수 있는 자격 증명을 모두 교체해야 함
    • GitHub 토큰, npm 토큰, 클라우드 자격 증명, SSH 키, CI/CD 비밀정보가 포함됨
  • GitHub에서는 비인가 저장소 생성과 비정상 workflow를 점검해야 함
    • .github/workflows/ 아래의 예상치 못한 파일, 의심스러운 workflow 실행, artifact 다운로드, Dune 테마 이름 패턴 {word}-{word}-{3digits} 를 따르는 공개 저장소를 확인해야 함
    • 영향 가능성이 있으면 새로 게시된 저장소에서 아래 키워드를 점검해야 함
      • atreides
      • cogitor
      • fedaykin
      • fremen
      • futar
      • gesserit
      • ghola
      • harkonnen
      • heighliner
      • kanly
      • kralizec
      • lasgun
      • laza
      • melange
      • mentat
      • navigator
      • ornithopter
      • phibian
      • powindah
      • prana
      • prescient
      • sandworm
      • sardaukar
      • sayyadina
      • sietch
      • siridar
      • slig
      • stillsuit
      • thumper
      • tleilaxu
  • 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 변경을 모니터링해야 함

침해 지표

Hacker News 의견들
  • 최소 릴리스 대기 기간을 두는 것보다 더 나은 방어책이 있는지 궁금함
    .npmrcmin-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 기반 코드 변경 분석을 돌리고, 이상 징후가 있으면 사람이 검토하는 조합이 필요해 보임
      참고로 여기서 일하고 있음
  • 이번 사고는 빌드 파이프라인이 탈취돼서 오염된 패키지가 배포된 게 핵심임
    그래도 업무상 중요한 걸 npm에 얹고 있다면 의존성은 꼭 pinning하는 편이 낫다고 봄
    많은 개발자가 lockfile이면 충분하다고 여기지만, ^ 범위가 남아 있으면 lockfile 갱신 시 내가 명시적으로 고르지 않은 새 버전을 끌어올 수 있음
    회사 존립에 영향 줄 수 있는 시스템이라면 이 정도 번거로움은 감수할 가치가 있음

    • 반대로 생각하면, 나중 버전에서 보안 취약점이 수정됐을 때는 시스템이 그걸 자동으로 받아 적용해 주는 게 이상적이기도 함
  • https://github.com/doy/rbwBitwarden 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처럼 서드파티 의존성 없이도 대부분 해결되는 스택으로 갈 수도 있겠다고 봄
      반대로 언어 표준 라이브러리에 기능을 더 많이 넣는 쪽으로 갈 수도 있음
  • Bitwarden CLI 경험이 아주 나빴음
    bw list를 실행했더니 비밀번호 이름만 나올 줄 알았는데, 실제로는 비밀번호와 현재 TOTP 코드까지 전부 보여줬음
    더 무서운 건 서버에 ssh로 들어가 tmux 안의 weechat를 열어 보니, bw 명령의 전체 내용이 weechat 입력 히스토리에서 접근 가능했다는 것임
    왜 그런지 전혀 모르겠고, tmux와 weechat 세션을 넘어 계속 남아 있었고 서버를 재부팅해야만 사라졌음
    그 뒤로 bw CLI는 바로 지웠고 다시 설치할 생각도 없음
    참고로 터미널은 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 스크립트만 특별히 문제 삼는 건 여러 번 반박된 주장이라고 봄
      어차피 결국 실제 바이너리를 실행하게 됨
      그리고 정말 따지자면 설치 전에 패키지를 직접 받아 검사할 수도 있는데, 설치 프로그램의 동작 보장과 범위를 깊이 이해하지 못한다면 악성 코드를 내려받고 풀어놓는 과정을 어설프게 신뢰하는 쪽이 더 이상함
  • 러시아 로캘 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에서 아직 감을 못 잡은 건 클라우드 백업
      백업을 암호화하면 그 암호는 어디에 저장하고, 또 클라우드 제공자 비밀번호는 어디에 저장해야 하나 싶음
  • 이번 공격에서 특히 인상적인 건, 공격자들이 GitHub가 다운되지 않은 타이밍과 정확히 맞춰야 했다는 점임

  • 그래서 나는 서드파티 비밀번호 관리자를 아예 쓰지 않음
    보안, 업데이트, 백업 같은 걸 제대로 해줄 거라고 계속 믿어야 하기 때문임
    직접 stateless 비밀번호 생성기를 만들었고, 덕분에 기기 간 데이터 백업이나 동기화가 아예 필요 없음
    아주 길고 강한 마스터 비밀번호와 서비스명, 사용자명을 넣으면 적절한 파라미터의 scrypt 해시를 돌려 브루트포스를 사실상 불가능하게 만드는 방식임
    중요한 계정엔 2FA도 함께 씀