라이브러리를 가져다 쓴 게 아니라, 빌드 서버를 남에게 열어준 것

라이브러리를 가져다 쓴 게 아니라, 빌드 서버를 남에게 열어준 것 — 낚아챈 크레이트가 컴파일러를 심부름꾼으로 쓴다

분류: CVE · 공급망·개발도구 · 빌드시 임의코드실행 · CVE-2026-77651 · [표준]

덱. 러스트(Rust) 생태계의 인기 유틸리티 크레이트(crate, 러스트 패키지) arrayref의 특정 버전이, 프로젝트를 빌드(컴파일)하는 것만으로 악성 코드를 실행하도록 오염된 채 공개됐다고 알려졌습니다. 크레이트 본체가 아니라 그 뒤에 딸려 오는 불량 의존성(rogue dependency) 이 명령·제어 서버(C2)에 접속해 임의 코드 실행 통로를 여는 형태입니다. 남의 코드를 실행하려고 프로그램을 돌린 게 아니라, 그 코드를 컴파일한 순간 이미 당한 사례입니다.

개요

CVE-2026-77651은 러스트 크레이트 arrayref의 0.3.10 버전에 대한 공급망(supply-chain) 취약점으로 공개됐습니다. 공개된 설명에 따르면, 이 크레이트를 사용하는 프로젝트를 컴파일하는 시점에 악성 코드가 실행될 수 있습니다. 원인은 이 크레이트가 명령·제어(C2, command-and-control) 서버에 등록해 임의 코드 실행을 제공하는 불량 의존성을 함께 끌어오도록 오염됐기 때문입니다.

  • 영향 대상: 러스트 크레이트 arrayref 0.3.10 (crates.io 배포판) — ⚠️미확인(팩트체크 대상). 정확히 어느 버전이 오염됐고 어느 버전이 안전한지, 그리고 문제의 “불량 의존성”의 이름·배포 경로는 1차출처 대조 필요.
  • 취약점 클래스: 공급망 오염 — 빌드 타임에 실행되는 악성 코드가 C2에 접속해 임의 코드 실행 통로를 개방.
  • 트리거 시점: 프로그램 실행 시가 아니라 빌드/컴파일 시. 즉 취약 크레이트를 의존성에 넣고 cargo build(러스트 빌드 명령) 하는 것만으로 조건이 성립 — ⚠️미확인(팩트체크 대상). 빌드 스크립트(build.rs)인지 절차적 매크로(proc-macro)인지 등 정확한 실행 기전은 advisory로 확인 필요.
  • CVSS 3.1: 공개 점수·벡터 미확인 — ⚠️미확인(팩트체크 대상). NVD/advisory 직접 대조 필요. (공급망 임의코드실행은 통상 높은 점수로 분류되나, 이 초안에서 수치를 단정하지 않습니다.)
  • CWE: CWE-506(악성 코드 내장) 또는 CWE-829(신뢰할 수 없는 소스의 기능 포함) 계열로 분류될 가능성 — ⚠️미확인(팩트체크 대상).
  • 대응 상태: 오염 버전의 yank(배포 철회) 여부, 안전 버전, 침해된 배포 계정의 복구 여부 등 후속 조치 — ⚠️미확인(팩트체크 대상).

분석 배지. arrayref는 러스트에서 슬라이스의 일부를 고정 길이 배열 참조로 빌려 오는 매크로(array_ref! 등)를 제공하는, 널리 쓰이는 소형 유틸리티 크레이트로 알려져 있습니다. 이런 “작고 무해해 보이는” 저수준 크레이트일수록 수많은 프로젝트가 아무 의심 없이 의존성에 끼워 넣기 때문에 공급망 오염의 파급이 큽니다. 다만 개별 정황(오염 경로가 계정 탈취인지·타이포스쿼팅인지, 정확한 배포일, 침해 규모)은 이 초안에서 직접 fetch로 확증하지 못했으므로 미확인으로 남깁니다.

기술 배경 (30초)

러스트의 패키지 관리자 Cargo(카고) 는 프로젝트의 Cargo.toml에 적힌 의존성들을 crates.io 같은 저장소에서 내려받아 함께 컴파일합니다. 여기서 핵심은 러스트가 빌드 과정 자체에서 임의 코드를 실행할 수 있는 통로를 정식으로 제공한다는 점입니다.

  • 빌드 스크립트(build.rs): 크레이트는 컴파일 전에 실행되는 빌드 스크립트를 둘 수 있습니다. 원래 목적은 C 라이브러리 링크·코드 생성 같은 준비 작업이지만, 이 스크립트는 개발자의 컴퓨터에서 그냥 하나의 프로그램으로 실행됩니다.
  • 절차적 매크로(proc-macro): 컴파일 타임에 코드를 생성하는 매크로 역시 컴파일러 안에서 실제 코드로 돌아갑니다.

즉 러스트에서 “의존성을 추가한다”는 것은 단순히 함수를 빌려 오는 게 아니라, 그 크레이트(와 그 크레이트가 다시 끌어오는 모든 하위 의존성)의 코드를 내 빌드 환경에서 실행할 권한을 준다는 뜻에 가깝습니다. 그리고 대부분의 개발자는 자기가 직접 적은 의존성 하나가 뒤에서 수십 개의 하위 의존성(transitive dependency) 을 딸려 온다는 사실을 매번 확인하지 않습니다. CVE-2026-77651은 바로 이 “직접 적지 않은 뒤쪽 의존성”에 악성 코드가 숨어든 사례입니다.

CVE 분석 요약

공개된 설명을 근거로 정리하면, 문제의 본질은 취약점(버그) 이 아니라 의도적으로 심어진 악성 코드(malicious code) 입니다. 흐름은 다음과 같습니다.

  • A. 신뢰받는 이름에 오염이 실린다. 널리 쓰이는 arrayref라는 이름의 특정 버전(0.3.10)이, 정상 크레이트라면 필요 없을 불량 의존성을 추가로 참조하도록 변조된 채 배포됐습니다. 사용자는 익숙한 이름을 보고 평소처럼 가져다 씁니다.
  • B. 빌드가 곧 실행이다. 그 프로젝트를 컴파일하는 순간, 딸려 온 불량 의존성의 코드가 빌드 단계에서 실행됩니다(빌드 스크립트 또는 매크로 경로 — 정확한 기전은 ⚠️미확인). 프로그램을 배포·실행하기 전에 이미 개발자·CI 환경에서 코드가 돕니다.
  • C. C2에 등록해 원격 실행 통로를 연다. 실행된 악성 코드는 외부 명령·제어 서버(C2) 에 접속해 자신을 등록하고, 그 서버가 시키는 임의 명령을 받아 실행할 수 있는 상태가 됩니다. 개발자의 노트북, 또는 자동 빌드가 도는 CI 러너가 공격자의 손아귀에 들어갑니다.

개념 골격을 단순화하면 다음과 같습니다.

# 개념용 단순화 — 실제 소스/페이로드 아님
# Cargo.toml (피해 프로젝트)
[dependencies]
arrayref = "0.3.10"        # 익숙한 이름 — 하지만 이 버전이 오염됨

# arrayref 0.3.10 가 뒤에서 끌어오는 불량 의존성 (숨어 있음)
#   -> build.rs / proc-macro 가 "빌드 시점"에 실행됨
#   -> 외부 C2 서버에 접속·등록
#   -> 서버가 내려주는 임의 명령을 개발/CI 환경에서 실행

개념용 단순화 — 실제 페이로드/원본 코드 아님. 실제 크레이트명·의존성명·빌드 스크립트 내용·C2 주소는 옮기지 않았으며 확인하지도 않았습니다(⚠️미확인). 작동하는 악성 코드는 싣지 않습니다.

빠진 것은 대단한 방어 기술이 아니라 “내가 실제로 실행하게 될 의존성 트리를 내가 통제하고 있는가” 라는 단 하나의 신뢰 가정입니다. 개발자는 arrayref라는 라이브러리 한 줄을 신뢰했을 뿐인데, 실제로는 그 뒤에 매달린 이름 모를 코드에게 빌드 환경의 실행 권한을 통째로 내준 셈입니다.

공격 시나리오 · 영향도 + 대응방안

시나리오(개념). ① 공격자가 인기 크레이트 이름(arrayref)으로 오염된 버전을 배포합니다(계정 탈취·타이포스쿼팅 등 경로는 ⚠️미확인). → ② 피해자가 그 버전을 의존성에 넣고 cargo build를 실행합니다. → ③ 뒤따라온 불량 의존성이 빌드 시점에 실행돼 C2에 접속합니다. → ④ C2가 임의 명령을 내려 개발자 PC/CI 러너에서 코드를 실행합니다. 어느 단계에도 “이 코드를 실행해도 되는가”를 묻는 관문이 없어, 평범한 빌드 한 번이 곧 침해가 됩니다. (작동하는 페이로드·C2 세부는 싣지 않습니다.)

영향도. 확정적으로 말할 수 있는 범위는 취약 크레이트를 빌드하는 환경에서의 임의 코드 실행입니다. 그 환경이 개발자 개인 PC라면 자격증명·SSH 키·소스코드 탈취로, CI/CD 파이프라인이라면 배포 서명 키·클라우드 토큰 유출과 2차 공급망 확산(내가 만든 산출물에 다시 악성코드가 심겨 하위 사용자에게 퍼짐)으로 번질 수 있습니다(합리적으로 예상되는 후속 영향 — 분석 추정). 실제 침해 규모, 노출된 자산의 종류, 탈취 데이터의 범위는 공개 정황에 달려 있으며 ⚠️미확인(팩트체크 대상)입니다. 노출 전제는 “오염된 arrayref 버전을 의존성 트리에 포함한 채 빌드”입니다.

대응방안.

  1. 근본 — 오염 버전 제거·안전 버전 고정. arrayref(및 그 하위 의존성)를 쓰는 프로젝트라면 Cargo.lock을 열어 문제 버전(0.3.10로 알려짐 — ⚠️미확인) 이 잠겨 있는지 확인하고, 벤더/RustSec 권고가 지정하는 안전 버전으로 강제 고정(또는 오염 이전 버전으로 되돌림)합니다. 안전 버전 번호와 yank 여부는 이 초안에서 확인하지 못했으므로(⚠️미확인), advisory 원문의 지정 버전을 따르십시오.
  2. 완화(즉시 대응). 오염 버전으로 빌드가 한 번이라도 돈 개발/CI 환경은 침해된 것으로 간주하고, 노출됐을 자격증명·토큰·서명 키를 회수·재발급합니다. 빌드는 네트워크가 차단되거나 격리된 환경에서 돌려 빌드 스크립트가 외부로 나가는 통로를 막고, 의심 아웃바운드 연결을 점검합니다. 러스트 생태계라면 cargo audit(RustSec 취약 의존성 점검 도구)으로 알려진 오염 크레이트 포함 여부를 스캔합니다.
  3. 탐지 관점. 빌드 과정에서 발생하는 예상치 못한 아웃바운드 네트워크 연결(특히 낯선 호스트로의 접속), 빌드 스크립트가 만들어 내는 비정상 프로세스, CI 러너의 자격증명 접근 이상을 로그·EDR로 살핍니다. “컴파일 단계에서는 외부 통신이 없어야 정상”이라는 기준선을 세워 두면 이런 오염을 초기에 잡을 수 있습니다.
  4. 공급망 위생(재발 방지). 의존성 추가 시 하위 의존성 트리까지 확인하고, Cargo.lock을 커밋해 재현 가능한 빌드를 유지하며, 빌드를 최소 권한·네트워크 격리 환경에서 수행하는 정책을 둡니다.

논평 — 왜 이 실수가 반복되나

이 사건은 개별 라이브러리의 버그가 아니라 “의존성을 신뢰한다는 것의 진짜 의미” 에 관한 반복되는 교훈입니다. 우리는 npm의 event-stream, PyPI의 타이포스쿼팅 패키지, 그리고 여러 러스트 crates.io 오염 사건에서 똑같은 뿌리를 이미 여러 번 봤습니다 — 사용자는 “라이브러리를 가져다 쓴다”고 생각하지만, 현대 빌드 시스템에서 그 행위는 사실 “그 코드와 그 코드가 다시 끌어오는 모든 것을 내 환경에서 실행할 권한을 부여한다” 는 것입니다.

특히 러스트처럼 빌드 자체가 임의 코드 실행 지점(빌드 스크립트·매크로)을 정식 기능으로 갖는 생태계에서는, “실행하기 전에는 안전하다”는 직관이 통하지 않습니다. 컴파일이 곧 실행이기 때문입니다. 이는 인증 우회에서 “바깥의 주장을 서버가 다시 확인하지 않은 것”과 같은 계열의 실수 — 신뢰 경계를 넘어온 것을 자기 손으로 검증하지 않은 것 — 이며, 다만 그 경계가 “로그인 요청”이 아니라 “빌드 의존성 트리”로 옮겨 왔을 뿐입니다. 작은 유틸리티 크레이트일수록 검토 없이 끼워지므로, 공격자가 노리기에 가장 값싸고 파급이 큰 표적이 됩니다.

결론

한 줄 요약. 의존성을 추가하는 것은 함수를 빌려 오는 게 아니라 실행 권한을 나눠 주는 일입니다. CVE-2026-77651은 신뢰받는 이름 뒤에 숨은 불량 의존성이, 프로그램을 돌리기도 전에 빌드 한 번으로 개발·CI 환경을 C2에 넘긴 사례입니다.

이 오염된 버전은 철회·정정되겠지만, “빌드는 안전하다”는 착각과 “직접 안 적은 하위 의존성은 안 본다”는 습관은 다음 생태계·다음 패키지에서 또 사고를 냅니다 — 그래서 우리는 특정 크레이트가 아니라 “내가 실행하게 될 의존성 트리를 내가 통제하고 검증하는가” 라는 방법을 남깁니다.

References / 참고자료

  1. NVD — CVE-2026-77651 (이 글이 재구성한 1차출처 메타). 영향 대상·취약점 설명 근거. https://nvd.nist.gov/vuln/detail/CVE-2026-77651
    • 공개 설명 요지: 러스트 arrayref 크레이트 0.3.10이, 명령·제어 서버에 등록해 임의 코드 실행을 제공하는 불량 의존성을 포함하도록 오염돼, 이 크레이트를 사용하는 프로젝트를 컴파일할 때 악성 코드가 실행될 수 있음.
  2. RustSec Advisory Database / crates.io 보안 권고 — 오염 버전·안전 버전·yank 여부·불량 의존성명·CVSS·발견 경위의 1차출처. 본 초안에서 URL·수치·버전 직접 확증 못 함(⚠️미확인) — 팩트체크에서 advisory 원문으로 대조 필요.
  3. (배경) 공급망 오염 선례 — npm event-stream, PyPI 타이포스쿼팅, 러스트 crates.io 오염 사건 등, “의존성 신뢰 = 실행 권한 부여”라는 같은 뿌리를 보여 주는 사례들.

이 글은 위 1차출처 메타를 우리 관점에서 다시 쓰고 논평을 더한 초안입니다. 특정 문장·코드를 그대로 옮기지 않았으며, 작동하는 악성 코드·페이로드·C2 세부는 싣지 않았습니다. 크레이트 버전·불량 의존성명·빌드 실행 기전·CVSS·CWE 수치는 직접 확인하지 못했고(코드 예시는 개념 설명용), ⚠️미확인 표시 항목은 발행 전 독립 팩트체크에서 1차출처로 확증·정정되어야 합니다.