Nginx UI MCP 인증 누락으로 설정 조작 가능


요약
Nginx UI의 MCP 라우팅에서 /mcp와 /mcp_message의 인증 체인이 분리돼 있었다. 기본 IP 화이트리스트가 비어 있으면 허용으로 떨어져, 노출된 관리면에서는 MCP 도구 호출이 그대로 이어질 수 있다. 패치에서는 /mcp_message에도 AuthRequired()가 추가됐다.
| 항목 | 내용 |
|---|---|
| CVE | CVE-2026-33032 |
| 핵심 결함 | /mcp_message 인증 누락, 빈 IP whitelist의 fail-open 동작 |
| 영향 | 설정 파일 읽기·쓰기, reload/restart 호출 |
| 수정 포인트 | /mcp_message에 AuthRequired() 추가 |
| 릴리스 기준 | 2026-04-18 v2.3.7 |
Warning
버전 표기는 문서마다 다르다. NVD는 2.3.5 이하를 영향 범위로 적고, 다른 분석은 v2.3.4에서 수정됐다고 본다. 배포본에서는 버전 문자열보다 /mcp_message에 AuthRequired()가 실제로 들어갔는지 확인한다.
취약점 구조
핵심은 두 군데다.
/mcp는 인증과 IP 화이트리스트를 함께 탄다./mcp_message는 취약 버전에서 인증 없이 같은 MCP 핸들러로 들어간다.
여기에 IPWhiteList()의 기본 동작이 더해진다. 화이트리스트가 비어 있으면 차단이 아니라 통과로 처리된다. 즉, 관리 포트가 외부에 열려 있고 기본 설정이 남아 있으면, /mcp_message가 사실상 직접 제어면이 된다.
설정 변경 쪽은 nginx_config_add 흐름이 중요하다. 파일을 쓴 뒤 바로 nginx reload를 호출한다. 파일 쓰기와 설정 반영이 한 요청 흐름 안에서 이어진다.
취약 버전 흐름
/mcp
└─ 인증 + IP whitelist
└─ MCP 세션 생성
/mcp_message
└─ 인증 없음
└─ tools/call
├─ nginx_config_get
├─ nginx_config_add
├─ nginx_config_modify
├─ reload_nginx
└─ restart_nginx
패치의 본질도 단순하다. /mcp_message에 인증 미들웨어를 붙이고, 테스트에서 /mcp와 /mcp_message가 모두 같은 인증 결과를 내는지 확인한다. 로직 전체를 고친 것이 아니라, 빠진 경로 하나를 막은 형태다.
악용 조건과 흐름
Nginx UI 문서는 MCP를 /mcp 경로의 SSE 인터페이스로 설명하고, node_secret 쿼리 파라미터를 인증 값으로 사용한다. 공개 분석은 먼저 /mcp?node_secret=...로 세션을 열고, 이어서 /mcp_message?sessionId=...로 JSON-RPC 도구 호출을 보내는 흐름을 정리한다. 취약 상태에서는 두 번째 요청이 인증 없이 받아들여질 수 있다.
GET /mcp?node_secret=<redacted>
POST /mcp_message?sessionId=<redacted>
Content-Type: application/json
{"jsonrpc":"2.0","method":"tools/call","params":{"name":"nginx_config_get"}}
공개 자료에 나온 도구 범위는 읽기와 쓰기가 함께 있다. 읽기 쪽에는 nginx_config_get, nginx_config_list, nginx_status가 있고, 변경 쪽에는 nginx_config_add, nginx_config_modify, nginx_config_enable, nginx_config_rename, nginx_config_mkdir, reload_nginx, restart_nginx가 있다. nginx_config_add는 파일 저장 직후 reload를 건다.
탐지 포인트
네트워크
- 같은 소스에서
/mcp접근 뒤/mcp_messagePOST가 이어지는지 본다. - 요청 본문에
jsonrpc와tools/call이 보이면 MCP 도구 호출로 본다. - 도구명이
nginx_config_add,nginx_config_modify,reload_nginx,restart_nginx면 우선순위를 높인다.
엔드포인트
/mcp와/mcp_message의 인증 처리 차이를 확인한다.- 취약 버전에서는
/mcp_message가 인증 없이 라우팅된다. - 수정 버전에서는 두 경로가 같은 인증 체인을 탄다.
IPWhiteList가 비어 있는 상태를 경계한다. 빈 값은 deny가 아니라 allow로 처리된다.
서버
conf.d,sites-enabled,nginx.conf의 최근 변경과 nginx reload/restart 로그를 묶어서 본다.- 관리 포트 노출 여부를 먼저 확인한다.
- 기본 포트 9000이 외부에 열려 있으면 위험도가 높아진다.
ss -lntp | grep ':9000'
journalctl -u nginx --since "2026-03-15" | grep -Ei 'reload|restart'
find /etc/nginx -type f \( -path '*/conf.d/*' -o -path '*/sites-enabled/*' \) -mtime -7
대응 포인트
가장 먼저 볼 것은 관리면 노출이다. nginx-ui 관리 포트가 외부에 열려 있으면 닫고, MCP를 쓰지 않으면 비활성화한다. 패치 적용 여부는 버전 번호보다 /mcp_message 라우트에 AuthRequired()가 들어갔는지로 판단한다.
운영 조치도 같이 묶는다.
IPWhiteList를 비워 두지 않는다.conf.d,sites-enabled,nginx.conf에서 최근 변경 파일을 먼저 본다.- 의심 흔적이 있으면
node_secret, 관리자 계정, 관련 JWT secret을 함께 교체한다. - 백업 다운로드나 설정 export 경로가 열려 있는지도 같이 확인한다.
참고 자료
- GitHub Security Advisory - GHSA-h6c2-x2m2-mwhf
- NVD - CVE-2026-33032
- Pluto Security - MCPwn: A CVSS 9.8 One-Line MCP Bug That Hands Over Your Nginx to Anyone on the Network
- Rapid7 - CVE-2026-33032: Nginx UI Missing MCP Authentication
- Nginx UI 문서 - MCP Module
- raw - v2.3.3 mcp/router.go
- raw - v2.3.4 mcp/router.go
- raw - v2.3.3 internal/middleware/ip_whitelist.go
- raw - v2.3.3 mcp/config/config_add.go
- raw - fix commit 413dc63 / mcp/router_test.go
- GitHub Releases - 0xJacky/nginx-ui