- Eclipse iceoryx2의 iceoryx2-bb-container에서 unsafe 없이 잘못된 UTF-8 문자열을 만들 수 있는 결함(CVE-2026-92612)이 공개됐고, 0.10.0에서 해당 API를 없애 고쳤습니다.
- 심각도는 CVSS 4.0 1.0(Low)입니다. 당장 뚫리는 취약점이라기보다 "Rust라서 안전하다"는 가정이 의존성에서 깨질 수 있음을 보여준 사례입니다.
- 이런 unsound 권고는 cargo audit 기본 실행에서 CI를 멈추지 않습니다. 설정부터 확인하세요.
무슨 일이 있었나
iceoryx2는 Eclipse 재단의 Rust 기반 프로세스 간 통신(IPC) 미들웨어입니다. 문제는 여기에 딸린 컨테이너 크레이트 iceoryx2-bb-container의 String API였습니다.
권고문에 따르면 StaticString 등 문자열 타입이 safe 함수 as_mut_bytes()와 DerefMut로 내부 바이트 수정을 허용했고, as_str()은 그 바이트를 UTF-8 검증 없이 &str로 돌려줬습니다. 그 결과 애플리케이션 코드에 unsafe가 없어도 잘못된 문자열 참조로 정의되지 않은 동작(UB)을 일으킬 수 있었습니다.
Rust 표준 문서에 따르면 UTF-8이 아닌 &str은 만드는 순간이 아니라, 유효한 UTF-8을 가정하는 함수를 거치며 뒤늦게 UB로 이어질 수 있습니다. 원인과 증상이 멀리 떨어져 나타나는 유형입니다.
| 항목 | 내용 |
|---|---|
| 식별번호 | CVE-2026-92612, GHSA-8mq4-3mwq-qvg6, RUSTSEC-2026-0294 |
| 영향 버전 | iceoryx2-bb-container 0.10.0 미만 (GHSA·RustSec 기준) |
| 수정 | 0.10.0에서 as_mut_bytes·deref_mut 제거, 대체 API 없음 |
| 심각도 | CVSS 4.0 1.0 Low (Eclipse 산정), RustSec 분류 unsound |
| 영향 없음 | C/C++/C#/Python 바인딩, Zenoh·ROS 2 게이트웨이 |
수정 PR은 8월 31일 병합됐고, 9월 18일 0.10.0 릴리스와 함께 GHSA가 공개됐습니다. CVE와 RustSec 권고는 9월 21일 나왔고, 이전 버전 백포트 계획은 없습니다. CVE 레코드는 영향 범위를 'v0.8.0 초과'로 적었지만, GHSA는 0.8.0 이전 버전에서는 같은 API가 FixedSizeByteString에 있었다고 밝혔습니다. CVE 데이터의 영향 범위에는 상한이 없어, 이를 쓰는 스캐너는 수정 버전인 0.10.0도 영향으로 표시할 수 있습니다. 판단은 GHSA·RustSec 기준으로 하세요.
왜 우리 회사 문제인가
iceoryx2는 ROS 2·Zenoh 게이트웨이를 제공할 만큼 로보틱스처럼 저지연 통신이 필요한 시스템에서 쓰입니다. 사용처는 제한적이지만, Rust를 도입했거나 검토 중인 개발팀이라면 확인할 것이 세 가지 있습니다.
첫째, Rust의 메모리 안전 보장은 unsafe를 품은 라이브러리가 safe API의 경계를 제대로 지킬 때만 성립합니다. 이번 건은 라이브러리 내부의 가정(바이트는 항상 UTF-8)이 safe 함수 하나로 깨진 경우입니다. 우리 코드가 깨끗해도 의존성이 약속을 어기면 보장은 사라집니다.
둘째, 이런 결함은 RustSec에서 정보성(unsound) 권고로 분류되고, cargo audit은 이를 기본적으로 실패 처리하지 않습니다. cargo-deny도 기본값(workspace)에서는 직접 의존성의 unsound만 오류로 봅니다. iceoryx2-bb-container는 보통 iceoryx2를 통해 들어오는 간접 의존성이라 기본 설정으로는 놓치기 쉽습니다.
셋째, 수정 방식이 API 제거라 해당 API를 쓰는 코드는 버전을 올리면 컴파일 오류가 납니다. 업데이트가 밀리기 쉬운 구조입니다.
지금 순서대로 할 일
- 사용 여부 확인: 워크스페이스 루트에서
cargo tree -i iceoryx2-bb-container --workspace --all-features --target all을 실행합니다. 패키지를 찾지 못한다는 오류가 나오고 Cargo.lock에도 이 이름이 없으면 쓰지 않는 것이니 3번으로 넘어갑니다. 여러 버전이 섞여 있으면 패키지 이름 뒤에@버전을 붙여 지정합니다. - 사용 중이면 iceoryx2 자체를 0.10 계열로 올립니다. 예를 들어 iceoryx2 0.9.0은 컨테이너 크레이트를
^0.9.0으로 묶고 있어cargo update만으로는 0.10.0으로 넘어가지 않습니다. 올린 뒤 컴파일 오류가 나는as_mut_bytes()·가변 역참조 호출부가 수정 대상입니다. - CI에서 unsound를 실패로 격상: cargo audit은
cargo audit -D unsound또는.cargo/audit.toml의[output] deny = ["unsound"], cargo-deny는deny.toml에[advisories] unsound = "all"을 넣습니다. - unsafe 지도 그리기:
cargo geiger로 의존성별 unsafe 사용량을 뽑아 검토 순서를 정합니다. 숫자가 많다고 취약하다는 뜻은 아닙니다. - 우리 코드의 unsafe 가두기: 필요 없는 크레이트에는
#![forbid(unsafe_code)]를 겁니다. unsafe가 필요한 크레이트는 Cargo.toml에[lints.clippy]undocumented_unsafe_blocks = "deny"를 넣어// SAFETY:주석을 강제하고, CI에서cargo clippy를 돌립니다. 이 린트는 기본값이 꺼져 있어 켜야 동작합니다.str::from_utf8_unchecked같은 unsafe 함수는 금지 대상이 아니라, UTF-8 보장 근거를 주석으로 남기고 리뷰에서 확인할 대상입니다. - 경계 함수는 Miri로 테스트:
rustup +nightly component add miri후cargo +nightly miri test로 실행합니다. Miri는 nightly 전용이고 FFI 호출은 대부분 지원하지 않으며 실행된 경로만 검사하므로, 경계 함수 전용 테스트를 따로 둡니다.
자가점검
- Cargo.lock에 iceoryx2-bb-container 0.10.0 미만이 남아 있지 않은가
- CI의 cargo audit이 unsound 권고에서 실패하도록 설정돼 있는가
- cargo-deny를 쓴다면 unsound 설정이 간접 의존성까지 포함하는가
- unsafe를 쓰는 의존성 목록과 검토 담당자가 정해져 있는가
- 우리 코드의 unsafe 블록마다 안전 근거 주석이 있는가
- unsafe 경계 함수가 Miri 테스트를 통과하는가
이 글의 점검은 누가 해야 하나
이번 결함은 코드와 의존성 층의 문제라 URL 기반 외부 점검으로는 드러나지 않습니다. 위 1~6번은 Rust를 쓰는 개발팀이 직접 하는 것이 가장 빠르고, 3·5·6번은 CI에 넣어 두면 다음 권고도 놓치지 않습니다. 오픈소스 의존성 관리 전반은 공급망 보안 체크리스트와 SBOM 준비 가이드에서 이어서 볼 수 있습니다.
그 코드로 만든 서비스가 실제 공격 경로로 이어지는지는 별도 검증 영역입니다. 보안 전문 기업 SENTRIX의 모의해킹은 점검 깊이(블랙박스·그레이박스·화이트박스)와 대상 범위를 상담 단계에서 합의하고 레드팀이 공격자 관점에서 직접 검증합니다.
오늘 CI에 -D unsound 한 줄부터 추가해 보세요.