포스트

NGINX HTTP/3 구성 의존 CVE 대응 체크리스트

ngx_http_v3_module·OpenSSL·TLS handshake 경로 조합에 따라 갈리는 NGINX HTTP/3 취약점(CVE-2026-90439) 점검·완화 절차를 정리합니다.

NGINX HTTP/3 구성 의존 CVE 대응 체크리스트

구성 의존 취약점은 “업그레이드”만으로는 닫히지 않습니다

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 ... quic6
  • reuseport는 멀티 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 모듈을 빌드에서 제거

최종적으로는 안전 버전으로 이동해야 합니다.

  • Open Source: nginx-1.30.5(stable) 또는 nginx-1.31.6(mainline) 이상2
  • 취약/안전 범위는 보안 공지 페이지 기준으로 판단1

만약 조직 정책상 “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 on
  • proxy_pass
  • proxy_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)을 함께 봐야 실제 리스크가 결정됩니다. 이 구조를 이해하고 나면, 업그레이드가 늦는 조직에서도 “끄기/막기/제거하기”로 운영 위험을 먼저 닫고, 그 다음에 버전을 올리는 순서가 합리적으로 잡힙니다.

참고 자료

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.