---
title: "Matrix의 Rust 암호화 라이브러리 Vodozemac에서 심각한 암호학적 결함 발견 — all-zero 공개키로 E2EE 완전 무력화"
published: 2026-02-17T23:49:12.000Z
canonical: https://jeff.news/article/941
---
# Matrix의 Rust 암호화 라이브러리 Vodozemac에서 심각한 암호학적 결함 발견 — all-zero 공개키로 E2EE 완전 무력화

보안 연구자 Soatok이 Matrix의 Rust 암호화 라이브러리 Vodozemac에서 X25519 DH 구현 시 항등원(all-zero 공개키)을 거부하지 않는 심각한 취약점을 발견함. 공유 비밀이 0이 되어 E2EE 기밀성이 완전히 파괴되며, 그룹 채팅에서는 서버 운영자가 전체 기록을 읽을 수 있음. 2024년 libolm에서도 같은 연구자가 취약점을 발견했으나 Matrix는 Rust 재작성으로 해결했다고 주장했고, 결국 동일한 실수를 반복함.

## 배경: 2024년 디자뷔

- 보안 연구자 Soatok이 2024년 Matrix의 구 암호화 라이브러리 libolm을 **1분도 안 되는 시간** 동안 살펴보고 여러 사이드채널 취약점을 발견한 바 있음
- 당시 Matrix 측은 90일의 공개 유예 기간을 요청해놓고 아무것도 하지 않았고, 대체 클라이언트 개발자들에게 통보조차 하지 않았음
- Matrix는 "이미 알고 있었고, 그래서 새로운 Rust 라이브러리(Vodozemac)를 만들었다"고 주장함
- 2026년 2월, Soatok이 퇴근 후 저녁 시간에 그 "자랑스러운" Rust 라이브러리를 살펴본 결과 — 또다시 심각한 문제를 발견함

## 공개 타임라인: 왜 90일이 아닌 1주일인가

- **2026-02-11**: 취약점 발견 및 security@matrix.org에 보고
- **2026-02-12**: Matrix 측 "검토 후 답변하겠다" 회신
- **2026-02-17**: Matrix 측 "실질적 보안 영향 없다" 주장 → **같은 날 공개 디스클로저**
- 지난번에 90일을 줬더니 아무것도 안 했으므로, 이번에는 1주일만 줌
- 연구자 본인의 입장: "내 버그, 내 정책. 공짜 전문 노동을 제공받는 것만으로도 충분히 공정한 거래임"

## 핵심 취약점: Olm Diffie-Hellman이 항등원(all-zero 공개키)을 수용함

> [!WARNING]
> **심각도: HIGH** — X25519 DH 구현에서 `was_contributory()` 검증이 누락되어, 공개키를 전부 0으로 설정하면 공유 비밀(shared secret)이 항상 0이 됨. 이는 암호화 키를 누구나 유도할 수 있다는 의미로, **Olm 프로토콜의 기밀성이 완전히 파괴됨.**

### 기술적 설명

- Diffie-Hellman은 본질적으로 "지수를 이용한 곱셈"으로 이해할 수 있음
- 보안 엔지니어가 비대칭 연산을 볼 때 가장 먼저 물어보는 질문: **"입력 중 하나를 0으로 설정하면 어떻게 되는가?"**
- 0을 곱하면 결과는 항상 0 → 공유 비밀이 0 → 암호화 키가 예측 가능 → **보안이 제로**
- X25519 라이브러리(x25519-dalek)에는 이미 `.was_contributory()` 메서드가 있어서 all-zero 공유 비밀을 거부할 수 있음
- Vodozemac의 **다른 부분**(sas.rs, ecies/mod.rs)에서는 이 검증을 올바르게 수행하고 있음
- 그런데 정작 **E2EE의 핵심 코드 경로**에서는 이 검증이 빠져 있음
- 수정은 매우 간단함: `was_contributory()` 체크 한 줄 추가
- **구 라이브러리 libolm에도 동일한 취약점이 존재함** — Rust로 재작성했지만 같은 실수를 반복한 것

### RFC 9180의 명시적 요구사항

- X25519/X448의 경우 "DH 공유 비밀이 all-zero 값인지 반드시 검증하고, 해당 시 중단해야 한다"고 명시되어 있음
- 이는 Matrix팀이 무시하거나 모르고 있었던 업계 표준임

## 그룹 채팅(Megolm)에 대한 영향: 서버 운영자가 전체 채팅 기록을 읽을 수 있음

- Megolm(그룹 채팅) 세션에 새 멤버가 참여할 때, 세션 키가 Olm을 통해 암호화되어 전달됨
- 만약 누군가 all-zero 공개키로 그룹 채팅에 참여하면:
  - Olm 핸드셰이크가 예측 가능한 키로 수행됨
  - 세션 키가 사실상 평문으로 전달되는 것과 동일
  - **서버 운영자(또는 암호문에 접근 가능한 누구든)가 그룹 채팅의 전체 기록을 복호화할 수 있음**
- **경고 메시지나 오류가 전혀 표시되지 않음** — 클라이언트는 메시지가 안전하다고 표시하므로 **거짓된 보안감**을 줌
- "왜 누가 공개키를 0으로 설정하겠는가?"라는 반론에 대해:
  - 악의적인 사용자가 의도적으로 할 수 있음 (동기는 다양: 혼란 야기, 서버 관리자에 대한 블랙메일, 법 집행 통보 등)
  - 하드웨어 결함(cosmic ray bit flip), RNG 장애 등 우연히 발생할 수도 있음
  - **암호학적 보안은 심리학이나 게임 이론에 의존해서는 안 됨 — 공격자가 공격할 수 없어야 함**

## 기타 발견된 문제들

### V2 → V1 다운그레이드 공격 (심각도: LOW)
- V2는 전체 HMAC 출력을 사용하고, V1은 64비트로 절삭함
- 기본값이 V1이며, 공격자가 MAC을 단순히 절삭하면 V1으로 자동 다운그레이드됨
- 역직렬화 시에도 V1으로 자동 폴백 — V2의 존재 의미가 사실상 없음

### ECIES CheckCode: 가능한 값이 100개뿐
- 2자리 10진수로 구현되어 약 6비트 보안 수준 → MitM 공격 시 1% 성공률
- 보안 극장(security theater)에 가까운 기능

### 40개 이상 건너뛴 메시지 키 자동 삭제
- `MAX_MESSAGE_BYTES`가 40으로 하드코딩되어, 40개 이상의 메시지 키가 건너뛰어지면 나머지는 조용히 버려짐
- 해당 메시지는 **영구적으로 복호화 불가능**해지며, 클라이언트에서 설정 변경 불가

### Pickle 포맷의 결정적 IV
- 동일한 키로 두 번 `new_pickle()`을 호출하면 동일한 IV 생성 → 시맨틱 보안(semantic security) 상실
- CBC 모드라 GCM처럼 즉시 치명적이지는 않지만, 일관된 부주의를 보여줌

### Strict Ed25519 검증 기본 비활성화
- 2024년에 libolm에서 이미 보고된 동일한 문제
- Vodozemac은 strict 검증을 지원하지만 **기본값이 비활성화** — Cargo feature flag으로 명시적으로 켜야 함

## Matrix의 대응과 연구자의 반박

### Matrix의 주장
- "실질적 보안 영향 없음"
- 공격자(Mallory)가 두 정직한 참가자(Alice, Bob) 사이에서 MitM을 수행해야 한다고 주장
- 3DH의 세 가지 DH 출력이 모두 공격자에 의해 제어되어야 한다고 주장
- "위협 모델 범위 밖"이라고 주장

### 연구자의 반박
- **Matrix는 공격 시나리오를 완전히 잘못 이해하고 있음**: 공격자는 중간자가 아니라 **참가자 자체**
- 공격자가 Alice든 Bob이든, 자신의 키를 0으로 설정하면 3DH의 세 DH 출력 모두를 제어할 수 있음:
  - Alice가 공격자면 ia와 ea를 선택
  - Bob이 공격자면 IB와 EB를 선택
  - 결과: `0 || 0 || 0`이 HKDF의 입력이 됨
- Matrix의 위협 모델은 암호학적 공격에 대해 아무것도 명시하지 않음 — "범위 밖"이라고 주장하려면 명시적으로 기술해야 함
- 2024년과 동일한 플레이북: "이미 알고 있었지만 고치지 않기로 결정했고, 그 사실을 문서화하거나 알리지도 않았다"

### 연구자의 결론

> "Matrix 보안팀은 무능하거나(incompetent) 무책임하다(irresponsible). 다른 합리적 해석은 없다."

- 2024년에 자신들의 shit이 Hot하다고 주장했지만, 2026년 결론은 **"lukewarm shit"**
- "게이 퍼리한테 두 번이나 당하는 게 창피하지 않겠나" (원문: "getting dogged on by a gay furry more than once")

## EU와 관련 시사점

- **유럽연합이 Matrix를 정부 통신에 사용하고 있음**
- 이런 수준의 암호학적 결함이 있는 프로토콜을 정부 커뮤니케이션에 쓰고 있다는 것은 심각한 문제
- 2022년 Least Authority 감사에서 이미 일부 문제를 지적했으나 Matrix는 피드백을 반영하지 않음
- 2023년 독일 BSI가 자금 지원한 추가 감사도 있었으나, 연구자 평가로는 "일반적인 정적 분석 도구 수준"

> [!IMPORTANT]
> **핵심 교훈**: 암호화 라이브러리를 Rust로 재작성하는 것만으로는 보안이 보장되지 않음. 암호학적 전문성 없이 구현하면 같은 실수를 다른 언어로 반복할 뿐임. `was_contributory()` 한 줄의 검증이 빠져서 E2EE의 기밀성이 완전히 무너진 사례. 감사(audit)를 받았다고 해서 안전한 것이 아니라, 감사 결과를 실제로 반영했는지가 중요함.

## 참고 링크

- [원문 블로그 포스트](https://soatok.blog/2026/02/17/cryptographic-issues-in-matrixs-rust-library-vodozemac/)
- [PoC Gist (공개 후 공유)](https://soatok.blog/2026/02/17/cryptographic-issues-in-matrixs-rust-library-vodozemac/)
- [RFC 9180 — HPKE (all-zero DH 거부 요구사항)](https://www.rfc-editor.org/rfc/rfc9180)

## 핵심 포인트

- X25519 DH에서 was_contributory() 검증 누락 — all-zero 공개키 수용 시 공유 비밀이 0이 되어 암호화 무의미
- 그룹 채팅(Megolm)에서 악의적 참가자가 all-zero 키로 참여하면 서버 운영자가 전체 채팅 기록 복호화 가능
- V2→V1 다운그레이드 공격, 결정적 IV, Ed25519 strict 검증 기본 비활성화 등 추가 문제 다수 존재
- Matrix 측은 '실질적 영향 없음'이라 주장했으나 공격 시나리오를 잘못 이해한 것으로 드러남
- EU가 정부 통신에 Matrix를 사용하고 있어 파급력이 큼. 2022년 감사에서 이미 지적된 문제도 미반영

## 인사이트

Rust로 재작성하는 것은 메모리 안전성은 개선하지만 암호학적 정확성을 보장하지 않음. was_contributory() 한 줄이 빠져서 E2EE가 무너진 사례는, 암호화 구현에서 프로토콜 수준의 검증이 프로그래밍 언어 선택보다 훨씬 중요하다는 점을 보여줌. 감사를 받았는지보다 감사 결과를 반영했는지가 진짜 질문임.
