NGINX HTTP/3 구성 의존 CVE 대응 체크리스트
ngx_http_v3_module·OpenSSL·TLS handshake 경로 조합에 따라 갈리는 NGINX HTTP/3 취약점(CVE-2026-90439) 점검·완화 절차를 정리합니다.
구성 의존 취약점은 “업그레이드”만으로는 닫히지 않습니다
NGINX 쪽 보안 공지를 보면, 최근 몇 건은 전형적인 “버전이 취약/안전” 구조가 아니라 “특정 모듈 + 특정 설정 조합에서만” 터지는 유형이 눈에 띕니다. nginx.org 보안 공지 페이지에는 ngx_http_v3_module 사용 시 버퍼 오버플로우(CVE-2026-90439), ngx_http_ssi_module 사용 시 use-after-free(CVE-2026-56434)처럼 구성 의존이라는 전제가 깔려 있습니다.1
이런 유형은 대응이 늦어지기 쉬운 이유가 있습니다.
- NGINX 바이너리에 모듈이 “포함”된 것과, 런타임에서 그 기능이 “활성”인 것은 다릅니다.
- OpenSSL 버전(그리고 실제 런타임 링크)이 다르면 같은 NGINX 버전이라도 영향이 갈립니다.
- TLS handshake 경로는
ssl_certificate만으로 결정되지 않습니다.ssl_early_data, address validation(QUIC), upstream/edge 구조, canary 방식 같은 운영 선택이 결과적으로 공격면을 열거나 닫습니다.
2026-09-15에 nginx-1.30.5(stable) / nginx-1.31.6(mainline)이 CVE-2026-90439 수정과 함께 릴리스됐고2, 같은 날 F5 쪽 릴리스 노트에도 ngx_http_v3_module의 TLS handshake 처리 중 제한적인 heap buffer overflow 가능성이 명시됐습니다3. 이건 “버전 올리세요”로 끝내기에는 운영 현실이 복잡합니다.
내 기준에서 이 글의 목적은 하나입니다. HTTP/3를 실험 도입해서 “부분 활성화” 상태로 운영 중인 팀이, 지금 당장(1) 무엇을 확인해야 하고, (2) 어떤 완화 옵션이 있으며, (3) 어떤 경우에 HTTP/3를 끄는 결정을 하는 게 합리적인지까지 닫는 것입니다.
CVE-2026-90439: ngx_http_v3_module + OpenSSL 조합에서만 열리는 문제
CVE-2026-90439는 nginx.org 보안 공지에서 “Buffer overflow when using ngx_http_v3_module”로 분류되어 있고, 취약/안전 버전 범위가 명확히 제공됩니다. 취약 범위는 1.29.2–1.31.5, 안전 버전은 1.31.6+ 및 1.30.5+입니다1.
하지만 “버전만”으로는 부족합니다. F5 릴리스 노트에 붙은 조건을 그대로 읽어야 합니다.
- HTTP/3 사용 중
- OpenSSL 3.5.0 이하
- 특정 configuration에서
- TLS handshake 처리 중
- 제한적인 heap buffer overflow 가능
- 비결정적(non-deterministic)이며 공격자가 제어하기 어렵다
이 내용은 NGINX Releases에 그대로 들어가 있습니다. 또 GitHub Advisory Database에도 거의 같은 문구가 올라와 있습니다4.
여기서 운영 관점의 핵심은 두 가지입니다.
1) 공격자가 완전 제어할 수 없다는 표현은 “안전하다”가 아니라 “재현이 어렵고 조건이 있다”에 가깝습니다. 운영팀 입장에서는 worker crash/restart로 이어질 수 있다는 것 자체가 가용성 사건입니다.
2) “TLS handshake 처리 중”이라는 말은, 평상시 요청 처리보다 더 앞단에서(worker가 connection을 받아들이는 순간) 터질 수 있다는 뜻입니다. 즉, WAF 룰/라우팅/업스트림 검증으로 막을 수 있는 영역이 아닙니다. 더 앞단에서 닫아야 합니다.
HTTP/3가 켜져 있는지: “모듈 존재”와 “실제 노출”을 분리해서 봐야 합니다
HTTP/3가 켜져 있는지 여부는 세 겹으로 갈라집니다.
1) 빌드 타임: 바이너리에 HTTP/3 모듈이 들어갔는가
NGINX는 --with-http_v3_module로 HTTP/3 지원을 빌드할 수 있고, 이 모듈은 기본 빌드에 항상 들어가는 것이 아니라 “built by default가 아니다”라고 configure 문서에 명시돼 있습니다5.
현업에서는 다음 두 케이스가 섞입니다.
- vendor 패키지(배포판/이미지)가 이미 HTTP/3를 포함한 빌드일 수 있다
- 소스 빌드(또는 Open Source subscription/Plus)에서 직접
--with-http_v3_module을 켜서 넣었을 수 있다
nginx.org QUIC 문서에는 “1.25.0부터 QUIC/HTTP/3 지원이 가능하며 Linux binary packages에 포함된다”는 문장이 있어, “나는 소스 빌드 안 했으니 HTTP/3 없을 것” 가정이 깨질 수 있습니다6.
2) 런타임 설정: UDP 리스너(QUIC)가 실제로 열렸는가
QUIC/HTTP/3는 TCP가 아니라 UDP 위에서 돌아갑니다. nginx.org QUIC 문서 기준으로는 listen에 quic 파라미터를 붙여야 HTTP/3 over QUIC가 활성화됩니다6.
즉, 다음이 진짜 신호입니다.
listen 443 quic;또는listen 443 quic reuseport;- 서버가 443/udp를 실제로 listen 중
- 인프라 레벨에서 443/udp가 외부에 열려 있음(Security Group/LB/방화벽)
부분 활성화 팀은 종종 다음의 중간 상태에 걸립니다.
- 설정에는
listen ... quic이 있는데, 네트워크에서 UDP 443이 막혀 있어 “있지만 안 되는” 상태 - Alt-Svc 헤더만 광고하고 실제 QUIC 리스너는 안 열어 둔 상태
- 일부 vhost만 QUIC 리스너를 열어 둔 상태(멀티테넌트에서 흔함)
이 중 어떤 상태든, CVE-2026-90439 관점에서는 “QUIC listener가 실제로 외부에서 도달 가능하냐”가 가장 결정적입니다.
3) TLS 라이브러리: 런타임에서 어떤 OpenSSL(또는 대체 라이브러리)을 쓰는가
CVE-2026-90439는 조건에 OpenSSL 3.5.0 이하가 붙습니다34.
여기서 함정은 두 가지입니다.
nginx -V가 출력하는 OpenSSL 버전은 “빌드 환경/링크 정보”에 가까운데, 동적 링크 환경에서는 런타임에 로딩되는 libssl이 달라질 수 있습니다.- nginx.org QUIC 문서는 OpenSSL 3.5.1 이상을 권장하고, 그 미만에서는 “OpenSSL compatibility layer”를 쓴다고 적어 두었습니다6. 즉, OpenSSL 3.5.0 이하로 QUIC를 운영 중인 환경이 실제로 존재할 가능성이 높습니다.
정리하면, CVE-2026-90439는 아래의 AND 조건으로 보는 게 운영 판단에 맞습니다.
- NGINX 버전이 1.29.2–1.31.5 범위인가?1
ngx_http_v3_module이 빌드에 포함되어 있는가?5- QUIC/HTTP/3가 런타임 설정에서 활성이고(UDP listener 포함), 외부에서 도달 가능한가?6
- OpenSSL이 3.5.0 이하인가(혹은 그 이하로 보이도록 링크/패키징돼 있는가)?3
이 중 하나라도 아니면 “이 취약점의 실제 노출”은 크게 줄어듭니다. 반대로 네 가지가 모두 맞으면, 재현 난이도/비결정성 여부와 별개로 운영 리스크로 취급하는 편이 맞습니다.
15분 점검: HTTP/3 부분 활성화 환경을 기준으로 한 체크리스트
여기서는 도구를 복잡하게 만들지 않고, SSH 접속만 가능하면 바로 돌릴 수 있는 점검을 기준으로 정리합니다.
A. 버전/빌드/모듈 포함 여부: nginx -V
먼저 NGINX 바이너리 자체를 봅니다.
1
nginx -V 2>&1 | tee /tmp/nginx-V.txt
여기서 확인할 항목은 최소 3개입니다.
1) NGINX 버전: nginx version: nginx/1.31.5 같은 줄 2) configure arguments에 --with-http_v3_module 존재 여부5 3) built with OpenSSL ... 또는 유사 출력에서 OpenSSL 버전
부분 활성화 팀에서 자주 놓치는 포인트는 “예전에 실험하느라 빌드 플래그를 켜 둔 채로, 지금은 설정에서만 꺼뒀다”입니다. 이 상태는 보안 이슈마다 다르게 작동합니다.
- 이번 CVE-2026-90439는 “HTTP/3 사용 중”이 조건이어서, 단순히 모듈만 포함됐다고 곧바로 노출이라고 보긴 어렵습니다3.
- 하지만 운영 정책 측면에서는, 모듈이 포함돼 있으면 누군가 설정 한 줄로 기능을 켤 수 있는 상태이므로 change control 관점에서 위험이 남습니다.
B. 설정 전체를 실제 include 결과로 확인: nginx -T
NGINX 설정은 include 지옥이 흔합니다. grep만으로는 누락이 생깁니다.
1
nginx -T 2>/tmp/nginx-T.err | tee /tmp/nginx-T.txt
그리고 QUIC/HTTP/3 신호를 뽑습니다.
1
2
3
4
5
# 1) QUIC listener
grep -nE 'listen\s+[^;]*\bquic\b' /tmp/nginx-T.txt || true
# 2) http3 관련 디렉티브 흔적(버전마다 다르지만, 키워드 기반으로)
grep -nE '\bhttp3\b|\bquic_\b|\bssl_early_data\b|\bAlt-Svc\b' /tmp/nginx-T.txt || true
nginx.org QUIC 문서에서 직접 언급하는 설정 키워드는 다음입니다.
listen ... quic6reuseport는 멀티 worker에서 권장6- address validation을 켜는
quic_retry on;6 - 0-RTT를 켜는
ssl_early_data on;6
CVE-2026-90439이 “TLS handshake 처리 중”이라는 표현을 쓰는 만큼, ssl_early_data 같은 handshake 경로 확장 옵션이 켜져 있는지 여부는 반드시 확인해야 합니다. 다만 공개된 문서만으로는 “이 옵션이 취약 트리거 조건이다/아니다”를 단정할 수는 없습니다.3
C. 커널/프로세스 레벨에서 UDP 443 리스닝 여부 확인
설정이 있어도 실제로 UDP 리스너가 안 열릴 수 있습니다. 반대로 설정이 없는데도 다른 include에서 열릴 수 있습니다.
1
2
3
4
# UDP 443 리스닝 확인
ss -u -lpn | grep -E ':443\b' || true
# 시스템 방화벽(예: nftables/iptables/ufw)까지는 환경마다 달라서, 여기서는 최소한 포트 노출만 확인
여기서 UDP 443이 떠 있으면, QUIC가 “서버 프로세스 레벨에서” 노출된 것입니다.
D. 로드밸런서/프록시 앞단의 UDP 경로 확인(현실적으로 가장 중요)
NGINX 앞단에 L4/L7 LB가 있으면, QUIC는 중간에서 잘려 나가는 경우가 많습니다. 부분 활성화 팀이 가장 자주 만드는 위험한 상태가 “edge LB에서는 UDP를 열어 둔 상태인데 backend는 테스트용 설정을 남겨 둔 상태”입니다.
- LB가 UDP 443을 pass-through 하는가
- Security Group / NACL / 방화벽이 UDP 443을 허용하는가
- CDN을 쓰는 경우, CDN이 origin까지 HTTP/3를 전달하는가(대부분은 여기서 끊깁니다)
이건 코드로 자동화하기 어렵고, 결국 인프라 정의(Terraform/CloudFormation/Kubernetes Service)와 실제 런타임을 함께 확인해야 합니다.
E. “Alt-Svc만 켜 둔” 상태 점검
부분 활성화에서 종종 Alt-Svc: h3=":443"; ma=...만 넣고, 실제 QUIC listener는 안 열어 둔 상태가 있습니다. 이 상태는 기능적으로는 실패율/지연을 만들고, 보안적으로는 “QUIC 리스너가 없으면 CVE-2026-90439의 트리거 면이 줄어든다” 쪽으로 해석할 수 있습니다. 다만 운영에서는 반대로, 누군가 QUIC listener를 켰을 때 고객 영향이 급격히 생기므로 change control 대상입니다.
Alt-Svc를 설정에서 찾는 것만으로는 부족하고, 실제 응답 헤더로도 확인하는 편이 낫습니다.
1
2
3
curl -skI https://YOUR_DOMAIN \
| tr -d '\r' \
| grep -i '^alt-svc:' || true
완화 옵션: 기능 비활성화/빌드 옵션/롤백을 “선택지”로 만들기
CVE-2026-90439은 패치된 NGINX 버전(1.31.6+, 1.30.5+)이 존재합니다12. 그럼에도 운영에서 즉시 업그레이드가 안 되는 팀은 늘 존재합니다. 이 경우 완화 전략을 단계별로 쪼개야 합니다.
여기서는 “NGINX 버전을 올리는 것”을 최종 목적지로 두되, 그 전까지의 임시 방어막을 실제 실행 단위로 정리합니다.
1단계(즉시): HTTP/3를 꺼서 노출면 자체를 없애기
이 취약점은 ngx_http_v3_module 사용 + HTTP/3 사용이 전제입니다34. 가장 확실한 임시 완화는 “HTTP/3를 끄는 것”입니다.
실행은 3종 세트로 보아야 합니다.
1) 설정에서 QUIC listener 제거
1
2
3
4
5
# (예시) 제거 대상
# listen 443 quic reuseport;
# 남겨야 하는 TCP TLS 리스너
listen 443 ssl;
listen ... quic이 핵심 스위치입니다6.
2) 네트워크에서 UDP 443 차단
- LB/SG/방화벽에서 UDP 443을 닫습니다.
- “설정 실수로 다시 켜져도 도달 불가” 상태가 되므로, 운영 사고를 크게 줄입니다.
3) Alt-Svc 광고 중단
- 브라우저는 Alt-Svc를 캐시하기 때문에, 과거에 광고했으면 일정 시간(또는 ma 값) 동안 재시도할 수 있습니다.
- 광고만 끄면 신규 캐시는 줄지만, 네트워크에서 UDP를 닫아 두지 않으면 실수로 노출이 다시 생길 수 있습니다.
내 경험상, 1)+2)가 들어가면 대부분의 실험 도입 리스크는 통제됩니다. 특히 2)는 “설정 실수”를 안전하게 만드는 운영 장치입니다.
2단계(단기): OpenSSL/QUIC 라이브러리 조합을 정리해서 “조건부 노출”을 줄이기
nginx.org QUIC 문서는 OpenSSL 3.5.1 이상을 권장하고, 그 미만에서는 compatibility layer가 동작한다고 적어 둡니다6. CVE-2026-90439의 조건이 “OpenSSL 3.5.0 이하”인 점을 고려하면, 최소한 다음을 해야 합니다.
- 런타임에 어떤 OpenSSL이 로딩되는지 재확인
- 컨테이너/호스트 단에서 OpenSSL 업데이트가 NGINX에 실제로 반영되는지 확인
여기서 조심할 점은, “OpenSSL만 올리면 이 CVE가 해결된다”를 문서가 직접 말해주지는 않는다는 것입니다. 공개된 문구는 “특정 OpenSSL 버전 이하에서 조건부로 발생할 수 있다”이지, “OpenSSL을 올리면 NGINX 취약점이 패치된다”가 아닙니다3. 그래서 나는 보수적으로 접근합니다.
- OpenSSL 업데이트는 “노출 조건을 줄일 수 있는 조치”로 취급
- NGINX 패치 버전으로의 이동은 별도의 목표로 유지
3단계(중기): NGINX 업그레이드 또는 HTTP/3 모듈을 빌드에서 제거
최종적으로는 안전 버전으로 이동해야 합니다.
만약 조직 정책상 “HTTP/3는 당분간 안 쓸 것”이 확정이라면, 더 깔끔한 선택지는 빌드에서 HTTP/3 자체를 제거하는 것입니다.
--with-http_v3_module을 넣지 않고 빌드하면 됩니다5.- 내부 표준 이미지(베이스 이미지)를 운영하는 팀이라면, 실험 브랜치 이미지와 운영 표준 이미지를 분리하는 편이 낫습니다.
이 방식의 장점은 구성 실수로 기능이 켜질 여지를 줄인다는 점이고, 단점은 vendor 패키지를 쓰던 팀에겐 빌드/배포 책임이 추가된다는 점입니다.
TLS handshake 경로는 운영에서 어떻게 달라지나
공개된 문서에서는 “특정 configuration”이라는 표현만 있을 뿐, 어떤 설정이 트리거인지 밝히지 않습니다34. 그래서 이 파트는 추정이 아니라 운영 점검 관점으로 정리합니다.
TLS handshake 경로가 달라지는 순간은 보통 다음 계열의 선택에서 발생합니다.
- 0-RTT 사용 여부: QUIC 문서에
ssl_early_data on;가 0-RTT enable 스위치로 제시됩니다6. - QUIC address validation 사용 여부:
quic_retry on;6. - 인증서/키 로딩 방식, 다중 인증서, OCSP stapling, client cert 검증 등(이 부분은 일반 TLS 영역이며, 구성 다양성이 큽니다)
중요한 건 “취약점 트리거가 이 중 무엇이다”가 아니라, HTTP/3 실험 도입팀이 흔히 아래처럼 설정을 섞어 두고, 그 상태가 그대로 production까지 들어오는 점입니다.
- 일부 서버 블록에서만 QUIC를 열고, 다른 서버 블록은 TCP만 열어 둠
- QUIC에서만 실험적으로
ssl_early_data on을 켜 봄 - QUIC에서는
reuseport를 넣고, TCP에서는 빼 둠
따라서 CVE-2026-90439 대응에서 “TLS handshake 경로”는 이렇게 다루는 편이 현실적입니다.
- HTTP/3가 켜져 있는 모든 server 블록에서
ssl_early_data,quic_retry상태를 명시적으로 기록 - canary 범위를 제한하고, QUIC를 켠 서버 블록을 운영 표준과 분리
- worker crash/restart 관측(로그/코어덤프/프로세스 재시작 카운터)을 HTTP/3 enable 변경과 연결해서 모니터링
운영에서 바로 쓰는 스캐너: nginx 설정 덤프 기반으로 위험 조합 뽑기
아래 스크립트는 “정교한 파서”가 아니라 “현장에서 빠르게 위험 신호를 모으기 위한 것”입니다. 목표는 10대/100대에 대해 동일한 기준으로 1차 분류를 하는 것입니다.
nginx-cve-precheck.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env bash
set -euo pipefail
OUT_DIR="${1:-/tmp/nginx-precheck}"
mkdir -p "$OUT_DIR"
NGINX_V="$OUT_DIR/nginx-V.txt"
NGINX_T="$OUT_DIR/nginx-T.txt"
nginx -V 2>&1 | tee "$NGINX_V" >/dev/null
nginx -T 2>/dev/null | tee "$NGINX_T" >/dev/null
nginx_version=$(grep -Eo 'nginx/[0-9]+\.[0-9]+\.[0-9]+' "$NGINX_V" | head -n1 | cut -d/ -f2 || true)
with_v3=$(grep -q -- '--with-http_v3_module' "$NGINX_V" && echo yes || echo no)
openssl_hint=$(grep -Eo 'OpenSSL [0-9]+\.[0-9]+\.[0-9]+' "$NGINX_V" | head -n1 || true)
quic_listen_lines=$(grep -nE 'listen\s+[^;]*\bquic\b' "$NGINX_T" || true)
alt_svc_lines=$(grep -nEi 'alt-svc' "$NGINX_T" || true)
early_data_lines=$(grep -nE '\bssl_early_data\b' "$NGINX_T" || true)
quic_retry_lines=$(grep -nE '\bquic_retry\b' "$NGINX_T" || true)
udp_443=$(ss -u -lpn 2>/dev/null | grep -E ':443\b' || true)
cat <<EOF
[nginx]
version: ${nginx_version:-unknown}
--with-http_v3_module: $with_v3
openssl (nginx -V hint): ${openssl_hint:-unknown}
[http3 exposure signals]
config: listen ... quic lines:
${quic_listen_lines:- (none)}
runtime: UDP :443 listeners (ss):
${udp_443:- (none)}
config: Alt-Svc related lines:
${alt_svc_lines:- (none)}
config: ssl_early_data lines:
${early_data_lines:- (none)}
config: quic_retry lines:
${quic_retry_lines:- (none)}
EOF
실행:
1
2
chmod +x ./nginx-cve-precheck.sh
./nginx-cve-precheck.sh
예상 출력(예시):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[nginx]
version: 1.31.5
--with-http_v3_module: yes
openssl (nginx -V hint): OpenSSL 3.5.0
[http3 exposure signals]
config: listen ... quic lines:
123: listen 443 quic reuseport;
runtime: UDP :443 listeners (ss):
UNCONN 0 0 0.0.0.0:443 0.0.0.0:* users:("nginx",pid=1234,fd=10)
config: Alt-Svc related lines:
210: add_header Alt-Svc 'h3=":443"; ma=86400' always;
config: ssl_early_data lines:
(none)
config: quic_retry lines:
310: quic_retry on;
이 정도 정보만 있어도, “HTTP/3가 실제로 열려 있나/Alt-Svc만 열려 있나/아예 흔적이 없나”를 빠르게 분류할 수 있습니다.
“부분 활성화” 팀이 특히 조심해야 하는 케이스
내가 여러 팀에서 봤던 HTTP/3 실험 도입의 전형적인 패턴은 아래입니다.
1) 성능/마케팅 목적: 브라우저에 HTTP/3를 보여주고 싶어서 Alt-Svc부터 넣음 2) 인프라 현실: UDP 443을 edge까지 관통시키는 데 시간이 걸림 3) 중간 상태: Alt-Svc는 배포됐는데 QUIC listener는 일부만 열리거나, 네트워크에서 막혀서 실질적으로는 실패 4) 몇 주 후: 실험을 접었는데 설정이 남아 있고, 누군가 다시 켜면 즉시 노출
이 패턴은 보안 관점에서 아주 애매합니다.
- 오늘은 UDP가 막혀 있어 안전해 보이지만
- 내일 LB 변경 하나로 UDP가 열리면 그 즉시 공격면이 생깁니다
따라서 CVE-2026-90439 대응에서 부분 활성화 팀이 만들어야 하는 산출물은 “현재 상태”가 아니라 “상태 전이가 통제되는가”입니다.
- HTTP/3를 계속 가져갈지(roadmap)
- 가져간다면 canary 범위/rollback 기준/관측 지표(worker restart 등)
- 안 가져간다면 모듈/설정/네트워크 레벨에서 완전 비활성화(재활성화가 change control을 통과해야만 가능)
CVE-2026-56434: SSI + proxy_pass + proxy_buffering off 조합 점검(부록이지만 같이 봐야 하는 이유)
nginx.org 보안 공지에서 CVE-2026-56434는 “Use-after-free when using ngx_http_ssi_module”로 분류되어 있고, 안전 버전은 1.31.3+ 및 1.30.4+, 취약 범위는 0.8.11–1.31.2로 제시됩니다1.
nginx news에서도 2026-07-15에 nginx-1.30.4와 nginx-1.31.3 릴리스가 CVE-2026-56434 수정을 포함한다고 적혀 있습니다2.
이 CVE를 같이 보는 이유는 단순합니다. 조직이 HTTP/3를 실험 도입하는 시기와, SSI 같은 오래된 기능을 “레거시 호환”으로 얹어 둔 상태가 겹치는 경우가 많습니다. 그리고 둘 다 구성 의존형이라 “취약점 관리의 방식”이 같습니다.
OpenCVE에 인용된 CNA 설명(원문은 F5 CNA 데이터 기반으로 보입니다)에서는 이 취약점이 다음 3개 설정이 함께 구성될 때 존재할 수 있다고 정리합니다.
ssi onproxy_passproxy_buffering off
또한 “upstream 응답을 제어할 수 있는 MITM 능력이 있는 공격자”라는 전제를 달고 있습니다7.
이 조건은 운영에서 이렇게 번역됩니다.
- upstream이 같은 VPC/같은 노드라서 MITM이 불가능하다고 가정하는 순간, 취약점의 우선순위가 내려갑니다.
- 반대로 upstream이 HTTP(평문)거나, cross-zone/cross-network로 나가고, 중간에 관측/변조 가능성이 열려 있으면(또는 upstream 자체가 신뢰하기 어렵다면) 우선순위가 올라갑니다.
여기서도 “버전 올리세요” 외에 가능한 완화가 있습니다.
SSI 모듈을 아예 빌드에서 빼기
NGINX configure 문서에는 --without-http_ssi_module 옵션이 명시되어 있습니다5. SSI를 기능적으로 제거할 수 있는 팀이라면 이것이 가장 강한 완화입니다.
설정 조합을 깨기: proxy_buffering을 끄지 않기
현실적으로 SSI를 당장 못 빼는 팀은 많습니다. 그 경우 “3개 조건이 동시에 만족”되는 조합을 깨면 됩니다.
proxy_buffering off를 제거해 기본값(on)으로 돌리거나- SSI가 필요한 location과 proxy가 필요한 location을 분리해서, 하나의 response path에 SSI+proxy+buffering off가 같이 걸리지 않게 구성합니다
이건 보안만이 아니라 성능/메모리 특성과도 맞물립니다. proxy buffering은 upstream 변동성을 흡수하는 장치라서, 대규모 트래픽에서는 대개 켜두는 쪽이 운영이 쉽습니다.
HTTP/3를 계속 가져갈지 결정할 때 보는 기준
HTTP/3 자체는 성능/모바일 환경에서 장점이 있지만, NGINX 기준으로는 “실험적(experimental)”로 문서화된 기간이 길었고, 최근 CVE들도 ngx_http_v3_module 주변에서 연속으로 나오는 흐름이 있습니다(이번 CVE-2026-90439도 그 연장선입니다).4
결정을 실무적으로 단순화하면 아래 질문으로 수렴합니다.
1) HTTP/3를 켰을 때 체감되는 KPI 개선이 실제로 측정됐는가
- 단순히 “지원됨”이 아니라, TTFB/전송 재시도/모바일 환경 지표가 개선됐는지
2) UDP 443 경로가 end-to-end로 안정적으로 구성돼 있는가
- CDN/LB/방화벽/노드까지 경로가 통제되는지
3) 취약점 대응 사이클을 HTTP/3 실험 속도에 맞출 수 있는가
- NGINX 업그레이드가 분기 단위로만 가능한 조직에서, 실험 기능을 production edge에 붙이면 비용이 커집니다
내 경우에는 3)이 안 맞는 조직에서는 “부분 활성화”를 최대한 짧게 가져가고, 결론이 안 나면 과감히 끄는 쪽이 비용이 낮았습니다. HTTP/3를 켜 둔 채로 “나중에 정리”는 거의 항상 빚으로 남습니다.
최종 체크리스트: 지금 상태를 분류하고, 완화/업그레이드 계획을 닫기
아래는 팀 내에서 그대로 티켓 템플릿으로 써도 되는 수준으로 정리한 항목입니다.
CVE-2026-90439(HTTP/3) 점검
- NGINX 버전이 1.29.2–1.31.5 범위인가? 안전 버전은 1.31.6+ 또는 1.30.5+1
nginx -V에--with-http_v3_module이 있는가?5- 설정 덤프(
nginx -T)에listen ... quic이 존재하는가?6 - 서버가 UDP 443을 실제 listen 중인가?(
ss -u -lpn) - 인프라에서 UDP 443이 외부에 열려 있는가?(LB/SG/방화벽)
- 응답에 Alt-Svc가 광고되는가?(
curl -I) ssl_early_data on또는quic_retry on같은 QUIC/TLS 확장 설정이 켜져 있는가?6- OpenSSL 버전이 3.5.0 이하로 보이는가? (CVE 설명 조건)3
CVE-2026-90439(HTTP/3) 완화 선택지
- QUIC listener 제거(
listen ... quic제거) + UDP 443 차단(가장 즉시성 높은 완화) - Alt-Svc 광고 중단
- 안전 버전(1.30.5/1.31.6+)으로 업그레이드2
- (HTTP/3를 접는 조직이라면) 표준 빌드에서
--with-http_v3_module제외로 재발 방지5
CVE-2026-56434(SSI) 점검
- NGINX 버전이 0.8.11–1.31.2 범위인가? 안전 버전은 1.31.3+ 또는 1.30.4+1
nginx -T기준으로 동일 path에서ssi on+proxy_pass+proxy_buffering off가 동시에 성립하는가?7
CVE-2026-56434(SSI) 완화 선택지
- SSI가 불필요하면
ssi off또는 SSI 사용 location 제거 proxy_buffering off제거(조합 깨기)- SSI를 조직에서 퇴역시킬 수 있으면
--without-http_ssi_module로 빌드에서 제거5
결론적으로, CVE-2026-90439은 “NGINX 버전”이 아니라 HTTP/3 활성화 여부 + OpenSSL/라이브러리 조합 + QUIC 노출(UDP 443)을 함께 봐야 실제 리스크가 결정됩니다. 이 구조를 이해하고 나면, 업그레이드가 늦는 조직에서도 “끄기/막기/제거하기”로 운영 위험을 먼저 닫고, 그 다음에 버전을 올리는 순서가 합리적으로 잡힙니다.
참고 자료
- NGINX 보안 공지 모음
- NGINX 뉴스(릴리스 공지)
- F5 NGINX 릴리스 노트(Plus/트랙 모델 포함)
- QUIC/HTTP/3 지원 문서(빌드/설정 팁, OpenSSL 3.5.1+ 권장)
- NGINX configure 옵션 레퍼런스(–with-http_v3_module, –without-http_ssi_module)
- GitHub Advisory Database: CVE-2026-90439 (GHSA-fjgw-pmcm-g7j7)
- OpenCVE: CVE-2026-56434(구성 조건 요약 포함)
- 예전 글: OpenSSL 3.0 EOL 이후 런타임 퇴역 운영 설계
- 예전 글: NGINX 1.31.5: Control API와 njs 리스크가 만나는 지점
https://nginx.org/en/security_advisories.html ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5 ↩︎6 ↩︎7 ↩︎8
https://docs.nginx.com/nginx/releases/ ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5 ↩︎6 ↩︎7 ↩︎8 ↩︎9
https://github.com/advisories/GHSA-fjgw-pmcm-g7j7 ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5
https://nginx.org/en/docs/configure.html ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5 ↩︎6 ↩︎7 ↩︎8
https://nginx.org/en/docs/quic.html ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5 ↩︎6 ↩︎7 ↩︎8 ↩︎9 ↩︎10 ↩︎11 ↩︎12 ↩︎13 ↩︎14