2026년 10월 14일 F5는 NGINX Open Source와 NGINX Plus에서 심각한 취약점 세 건(CVE-2026-97205, CVE-2026-93479, CVE-2026-15176)을 공개했다. 심각도는 최대 CVSS 9.2(치명적)이며, 각 취약점은 원격의 비인증 공격자가 워커 프로세스를 중단시키고 잠재적으로 임의 코드를 실행하게 할 수 있다. Xin은 안전한 Rust 구조를 통해 이런 종류의 버그가 구조적으로 발생할 수 없다고 주장한다.
취약점 세 건과 대응 방식
세 취약점은 모두 클라이언트 요청을 처리하는 NGINX 핵심 데이터 플레인에 있다. Xin은 이를 C의 수동 메모리 관리에서 비롯되는 세 가지 고전적 오류인 해제 후 사용(use-after-free), 관리되지 않는 버퍼 인덱싱, 경로 재작성 중 포인터 정렬 오류의 사례로 설명한다.
CVE-2026-97205: 비동기 I/O를 사용할 때 SSI에서 발생하는 해제 후 사용
NGINX에서는 비동기 파일 I/O(aio on;)와 서버 측 포함(SSI, Server Side Includes, ssi on;)을 함께 켜고 <!--#include virtual="..." --> 명령이 들어 있는 SSI 페이지를 처리하면 ngx_http_core_module에서 해제 후 사용 문제가 발생할 수 있다. 디스크 작업과 하위 요청 처리가 비동기로 이벤트 루프에 제어를 돌려주는 동안, NGINX의 내부 풀 할당자가 활성 SSI 하위 요청에 연결된 버퍼 메모리를 워커가 복사하거나 평가하기 전에 해제한다. 하위 요청이 끝나면 워커는 이미 풀에 반환됐거나 다시 할당된 메모리를 읽거나 쓰게 된다. 그 결과 힙 메모리 손상이나 워커 충돌이 발생할 수 있다.
F5는 AIO나 SSI 가운데 하나를 끄도록 권고한다. AIO를 끄면 부하가 걸린 상황에서 대용량 정적 파일과 동영상 스트리밍의 처리량이 낮아질 수 있고, SSI를 끄면 동적 HTML 조립 기능이 깨진다.
Xin은 SSI 파싱과 하위 요청 평가를 안전한 Rust로 구현했으며, 해당 코드는 #![forbid(unsafe_code)]를 적용하는 xin-engine/src/ssi.rs에 있다. Xin의 설명에 따르면 Rust의 컴파일 시점 빌림 검사기는 비동기 await 지점 전후의 모든 참조를 추적한다. 하위 요청 버퍼는 명시적 수명으로 관리하거나 스레드 안전 참조 카운트 핸들(Arc<T> 또는 Bytes)에 보관한다. 따라서 비동기 읽기나 평가 작업이 버퍼를 참조하는 동안 해당 버퍼가 해제되거나 재사용되는 상황은 컴파일 시점에 허용되지 않는다는 것이 Xin의 주장이다.
CVE-2026-93479: map 지시문에서 발생하는 힙 버퍼 오버플로
NGINX의 map 지시문에서 정규식 일치 결과를 평가할 때 힙 버퍼 오버플로가 발생할 수 있다. root나 접근 로그의 log_format 같은 지시문에서 주된 map 출력 변수보다 먼저 map 정규식 캡처 변수(예: $1, $2)를 참조하면 문자열 길이 계산과 버퍼 예약을 위한 포인터 계산이 서로 어긋난다. 조작된 HTTP 요청을 처리하는 과정에서 워커가 할당된 힙 버퍼의 경계를 넘어 확장된 변수 데이터를 쓸 수 있다.
F5는 설정을 점검하고 이름 없는 캡처를 모두 이름이 지정된 캡처로 바꾸며, 캡처 변수는 해당 캡처가 일치한 블록 안에서만 참조하도록 권고한다.
Xin은 map 블록과 정규식 캡처를 강한 타입의 중간 표현으로 컴파일한다. 관련 코드는 #![forbid(unsafe_code)]를 적용하는 xin-ir/src/pattern.rs와 xin-engine/src/rewrite.rs에 있다. Xin에 따르면 변수 해석에는 관리되는 가변 길이 Rust 문자열(String)과 경계를 검사하는 슬라이스 인덱싱을 사용한다. 원시 메모리 오프셋이나 검사하지 않은 포인터 오프셋을 쓰지 않으므로 범위를 벗어난 쓰기는 컴파일되거나 실행될 수 없다는 설명이다.
CVE-2026-15176: alias와 rewrite를 함께 쓸 때 발생하는 힙 버퍼 오버플로
location 블록에서 alias와 rewrite를 함께 사용하고 set, return 또는 접근 로그의 log_format 지시문에서 $request_filename 변수를 참조하면 NGINX가 대상 경로 문자열의 길이를 잘못 계산할 수 있다. 워커 메모리에서 최종 파일 시스템 경로를 만들 때 할당된 풀 청크가 재작성된 경로를 담기에 충분한지 확인하지 않고 C 포인터 연산을 수행해 힙 버퍼 오버플로가 발생할 수 있다.
F5는 재작성 규칙이 적용되는 곳에서 alias 지시문을 제거하고 $request_filename 참조를 없애도록 권고한다.
Xin은 파일 경로를 만들 때 안전한 경로 변환(PathBuf와 검사된 UTF-8 슬라이스)을 사용한다고 설명한다. 별칭이나 재작성 규칙을 적용하면 표준 할당자가 메모리를 자동으로 다시 할당한다. 모든 슬라이스 인덱싱에서 경계를 검사하므로 잘못된 경로 계산은 워커 메모리에 제어되지 않은 바이트를 쓰는 대신 검증 오류를 일으킨다는 주장이다.
C 프록시 구조에 대한 Xin의 주장
Xin은 이번 취약점들이 고립된 사례가 아니라고 주장한다. 2026년에만 NGINX에서 MP4 파서 오버플로, HTTP/3 해제 후 사용, 리졸버의 1바이트 초과 오류와 관련한 여러 보안 권고가 나왔다고 설명한다.
Xin이 지목하는 구조적 원인은 NGINX가 수동 메모리 풀(ngx_pool_t)과 C의 원시 포인터 조작에 의존한다는 점이다. 동시성이 높은 비동기 역방향 프록시에서 하위 요청의 수명, 청크 스트리밍 버퍼, 복잡한 정규식을 수동 포인터 연산으로 관리하면 수명이나 경계를 잘못 계산하는 예외 상황이 생긴다는 것이 Xin의 설명이다.
Xin은 보안 권고에 따라 AIO나 SSI를 끄거나 편리한 alias 및 map 설정을 해체해야 하는 경우가 있다고 지적한다. 이런 완화 조치는 메모리 버그를 피하기 위해 운영 효율을 낮추고 운영 환경의 설정을 깨뜨릴 수 있다고 주장한다.
Xin의 구성과 사용 방법
Xin은 NGINX 설정 호환성을 유지하면서 내부 C 런타임을 안전한 Rust로 대체하도록 만들었다고 소개한다. Xin이 제시한 기능과 구성은 다음과 같다.
- NGINX 설정 호환성: 기존
nginx.conf문법을 직접 읽고 지시문을 검증된 중간 표현으로 변환한다. - 안전한 Rust 데이터 플레인: HTTP/1 파서(
xin-h1), 설정 파사드(xin-facade-nginx), 중간 표현(xin-ir), 실행 엔진(xin-engine), DNS 리졸버(xin-resolver) 등 핵심 크레이트가 모두#![forbid(unsafe_code)]로 컴파일된다. - 가비지 컬렉션 일시 중단 없이 메모리 안전성을 제공한다. Xin은 벤치마크에서 C 기반 NGINX와 비슷하거나 더 높은 처리량을 보였으며, 여러 보안 취약점 유형을 없앤다고 주장한다.
Xin은 기존 설정을 다시 작성하거나 비동기 I/O를 끄지 않고 사용할 수 있는 대체 제품이라고 소개하며 다음 설치·확인·실행 명령을 제시한다.
# 1. Install Xin (xinginx)
curl -fsSL https://install.xinproxy.com/ | sh
# 2. Test your existing nginx.conf
xinginx -t -c /etc/nginx/nginx.conf
# 3. Run safely
sudo systemctl enable --now xinginx
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요