Executive Summary
CVE-2026-33032 is a critical authentication bypass vulnerability (CVSS 9.8) in nginx-ui, the widely used open-source web management interface for Nginx servers, discovered and dubbed MCPwn by Pluto Security. A missing authentication middleware call on the /mcp_message HTTP endpoint allows any network-accessible attacker to invoke all 12 of nginx-ui's Model Context Protocol (MCP) tools without any credentials — enabling Nginx configuration rewrites, service reloads, credential harvesting, and full web server takeover in as few as two HTTP requests. With approximately 2,689 instances publicly exposed on the internet and active exploitation confirmed in the wild, organizations running nginx-ui should treat this as an emergency patch event.
1. What Is This Vulnerability?
nginx-ui is a popular open-source dashboard (GitHub: 0xJacky/nginx-ui) that provides a graphical interface for managing Nginx web server configurations, SSL certificates, log streams, and more. In 2025–2026, nginx-ui added support for the Model Context Protocol (MCP), an emerging standard that allows AI tools and automation clients to interact with the application via a structured API.
The MCP integration exposed two new HTTP endpoints:
| Endpoint | Purpose |
|---|---|
/mcp |
Initiates an MCP session (SSE stream) |
/mcp_message |
Sends MCP tool invocations within a session |
The developers correctly protected /mcp with both IP whitelisting and authentication middleware. However, /mcp_message was protected only by IP whitelisting — and critically, when the IP whitelist is empty (the default configuration), the middleware interprets this as "allow all." Authentication middleware was never applied to /mcp_message.
The result: any attacker who can reach nginx-ui over the network can call any MCP tool directly, with no username, password, token, or session validation required.
Attack Vector
The attack is fully unauthenticated and requires only HTTP access to nginx-ui (typically port 80 or 443). The basic exploitation sequence:
- Establish a session — Send a GET request to
/mcpto receive asessionIdin the Server-Sent Events (SSE) stream. If the IP whitelist is empty (default), this succeeds without auth. - Invoke MCP tools — POST to
/mcp_messagewith thesessionIdand the desired tool name + parameters. No authentication headers are checked.
A concrete example of overwriting the default Nginx config:
POST /mcp_message?sessionId=<session_id> HTTP/1.1
Host: target-nginx-ui.example.com
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "write_nginx_config",
"arguments": {
"filename": "default.conf",
"content": "server { listen 80; root /var/www/attacker; }"
}
}
}
After writing the config, a follow-up call to the reload_nginx MCP tool applies the changes immediately.
Chained Exploitation with CVE-2026-27944
An additional vulnerability, CVE-2026-27944, exposes nginx-ui's encryption keys via the unauthenticated /api/backup endpoint. Attackers can extract the node_secret query parameter from the backup response and use it to obtain a valid sessionId directly — bypassing even the need for the SSE handshake. This reduces the full takeover to a deterministic two-request chain against default-configured instances.
Real-World Impact
- Recorded Future listed CVE-2026-33032 among 31 actively exploited vulnerabilities in March–April 2026.
- eSentire published a security advisory confirming observed exploitation campaigns targeting exposed nginx-ui instances.
- Attackers are using the vulnerability to rewrite Nginx configurations to proxy traffic through attacker-controlled infrastructure, enabling traffic interception, credential harvesting, and lateral movement into internal networks.
- Some intrusions have resulted in webshell deployment by writing malicious PHP/configuration content via the
write_nginx_configtool.
2. Who Is Affected?
Affected software: nginx-ui all versions prior to 2.3.4 with the MCP integration present.
Affected configurations:
- Any deployment where the MCP IP whitelist is empty (the default out-of-the-box setting)
- Instances accessible from the internet (Shodan shows ~2,689 exposed globally)
- Instances accessible from an internal network where attackers have already gained a foothold
Exposure by geography (Shodan data): China, United States, Indonesia, Germany, Hong Kong
Not affected:
- nginx-ui 2.3.4 and later (MCP endpoint authentication enforced)
- Deployments with MCP disabled entirely
- Deployments with a properly configured, restrictive IP whitelist (though upgrading is still strongly recommended)
3. How to Detect It (Testing)
Manual Testing Steps
-
Identify nginx-ui instances on your network by scanning for the nginx-ui login page (default ports 80/443; look for
<title>nginx ui</title>or the nginx-ui favicon hash). -
Attempt unauthenticated MCP session establishment:
curl -N -H "Accept: text/event-stream" \ "http://<target>/mcp"A vulnerable instance will return an SSE stream containing a
sessionIdwithout prompting for credentials. -
Attempt an unauthenticated MCP tool invocation using the
sessionIdfrom step 2:curl -s -X POST "http://<target>/mcp_message?sessionId=<SESSION_ID>" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'A vulnerable instance returns the list of available MCP tools (12 total) without authentication. A patched or properly secured instance returns a
401 Unauthorizedor403 Forbidden. -
Check the version (if you have read access to the filesystem or admin console):
- Version string shown in nginx-ui admin footer
/api/healthendpoint may expose version: look for"version"in the JSON response.- If version <
2.3.4, the system is vulnerable.
Automated Scanning
Tool: Nuclei (ProjectDiscovery)
Community templates for CVE-2026-33032 are available:
nuclei -u http://<target> -t cves/2026/CVE-2026-33032.yaml -v
Tool: Shodan CLI (for internet exposure enumeration)
shodan search 'http.title:"nginx ui" country:US' --fields ip_str,port,org
Tool: Nmap NSE (manual script)
nmap -p 80,443 --script http-nginx-ui-mcpwn <target_range>
Tool: Burp Suite — Passive scan will flag the unauthenticated SSE endpoint if the proxy intercepts the MCP handshake. For active scanning, add a custom scan check for /mcp returning 200 without Authorization headers.
Code Review Checklist (for nginx-ui maintainers / contributors)
- Confirm
AuthMiddleware(or equivalent) is applied to both/mcpand/mcp_messageroute handlers - Verify IP whitelist logic returns
deny all(notallow all) when the whitelist is empty - Audit all new route registrations to confirm security middleware is not accidentally omitted
- Check whether
/api/backupor similar endpoints expose secrets without authentication (CVE-2026-27944 companion fix)
4. How to Fix It (Mitigation)
Step-by-Step Remediation
-
Upgrade nginx-ui to version 2.3.4 or later — this is the primary fix. Version 2.3.4 was released on March 15, 2026, and applies authentication middleware to
/mcp_message.# Check current version nginx-ui --version # or check the admin panel footer # Stop nginx-ui service systemctl stop nginx-ui # Download latest release (adjust URL to your architecture) wget https://github.com/0xJacky/nginx-ui/releases/latest/download/nginx-ui-linux-amd64.tar.gz tar -xzf nginx-ui-linux-amd64.tar.gz mv nginx-ui /usr/local/bin/nginx-ui # Restart the service systemctl start nginx-ui # Verify new version nginx-ui --version -
If immediate upgrade is not possible — disable MCP or restrict access:
In your nginx-ui
app.iniconfiguration, disable the MCP integration entirely:[mcp] enabled = falseOr enforce a restrictive IP whitelist:
[mcp] enabled = true ip_whitelist = 127.0.0.1,10.0.1.5Restart nginx-ui after making this change.
-
Block the vulnerable endpoints at the network perimeter (belt-and-suspenders):
If nginx-ui is behind an Nginx reverse proxy (common setup), add location blocks to reject external access to MCP endpoints:
location ~ ^/mcp(_message)?$ { allow 127.0.0.1; allow 10.0.0.0/8; # internal only deny all; } -
Rotate credentials and audit Nginx configurations — if you suspect exploitation has occurred:
- Review all Nginx configuration files for unauthorized changes
- Check nginx-ui access logs for POST requests to
/mcp_messagefrom unexpected IPs - Rotate nginx-ui admin passwords and any credentials stored in configurations
- Check for unexpected processes or webshells in your web root
Code Fix Example
The root cause was a missing middleware application in the route handler. The fixed version adds AuthMiddleware to the /mcp_message route:
Before (vulnerable):
// Route registration in router.go (pre-2.3.4)
mcpGroup := r.Group("/mcp")
{
mcpGroup.GET("", middleware.IPWhitelist(), api.MCPHandler)
// Missing: AuthMiddleware on mcp_message
mcpGroup.POST("_message", middleware.IPWhitelist(), api.MCPMessageHandler)
}
After (patched):
// Route registration in router.go (2.3.4+)
mcpGroup := r.Group("/mcp")
{
mcpGroup.GET("", middleware.IPWhitelist(), middleware.AuthMiddleware(), api.MCPHandler)
mcpGroup.POST("_message", middleware.IPWhitelist(), middleware.AuthMiddleware(), api.MCPMessageHandler)
}
Additionally, the IP whitelist logic was corrected to default-deny when the whitelist is empty:
// Fixed IPWhitelist middleware behavior
func IPWhitelist() gin.HandlerFunc {
return func(c *gin.Context) {
whitelist := config.GetMCPIPWhitelist()
if len(whitelist) == 0 {
// FIXED: deny all when whitelist is empty (was: allow all)
c.AbortWithStatus(http.StatusForbidden)
return
}
// ... check if client IP is in whitelist
}
}
Configuration Hardening
Even after patching, apply these hardening steps:
- Restrict nginx-ui to non-public networks. The admin interface should never be directly internet-accessible. Place it behind a VPN or bastion host.
- Enable Two-Factor Authentication (2FA) in nginx-ui admin settings.
- Use a reverse proxy with mTLS for nginx-ui access in high-security environments.
- Set a restrictive MCP IP whitelist even on patched versions, as defense-in-depth.
- Enable audit logging to capture all configuration changes with timestamps and actor information.
5. How to Test the Fix (Validation)
Regression Test Scenarios
- Scenario A: After upgrading to 2.3.4+, repeat the unauthenticated MCP session probe — confirm
/mcpreturns401 Unauthorizedwithout a valid session token. - Scenario B: Confirm that a legitimate authenticated user can still use MCP tools normally after the upgrade (no broken functionality).
- Scenario C: Verify that disabling MCP in
app.inicauses both/mcpand/mcp_messageto return404 Not Found. - Scenario D: Verify Nginx configuration files have not been tampered with by comparing file hashes against a known-good baseline.
Security Test Cases
Test Case 1: Verify unauthenticated MCP session is rejected
- Precondition: nginx-ui upgraded to 2.3.4+; no session cookie / auth token in request
- Steps:
curl -N -H "Accept: text/event-stream" "http://<target>/mcp" - Expected Result: HTTP 401 or 403 — no
sessionIdreturned
Test Case 2: Verify unauthenticated tool invocation is rejected
- Precondition: nginx-ui 2.3.4+; attempt to POST to
/mcp_messagewith a fabricated/expired sessionId - Steps:
curl -X POST "http://<target>/mcp_message?sessionId=fake123" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' - Expected Result: HTTP 401 or 403 — tool list not returned
Test Case 3: Verify authenticated access still works
- Precondition: Valid admin credentials available; nginx-ui 2.3.4+
- Steps: Log in via the nginx-ui web interface and navigate to MCP-enabled features
- Expected Result: Full functionality accessible; no regressions
Automated Tests
import requests
NGINX_UI_URL = "http://your-nginx-ui-host"
def test_mcp_unauthenticated_blocked():
"""CVE-2026-33032 regression: unauthenticated /mcp access must be rejected."""
response = requests.get(
f"{NGINX_UI_URL}/mcp",
headers={"Accept": "text/event-stream"},
timeout=5,
stream=True
)
assert response.status_code in (401, 403), (
f"FAIL: /mcp returned {response.status_code} — unauthenticated access may be allowed"
)
print(f"PASS: /mcp returned {response.status_code} (authentication required)")
def test_mcp_message_unauthenticated_blocked():
"""CVE-2026-33032 regression: unauthenticated /mcp_message must be rejected."""
payload = {"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}
response = requests.post(
f"{NGINX_UI_URL}/mcp_message?sessionId=invalid",
json=payload,
timeout=5
)
assert response.status_code in (401, 403), (
f"FAIL: /mcp_message returned {response.status_code} — unauthenticated access may be allowed"
)
print(f"PASS: /mcp_message returned {response.status_code} (authentication required)")
if __name__ == "__main__":
test_mcp_unauthenticated_blocked()
test_mcp_message_unauthenticated_blocked()
6. Prevention & Hardening
Best Practices
- Never expose management interfaces to the internet. nginx-ui, like all admin dashboards, should be accessible only from trusted networks or via VPN. This single practice would eliminate exposure for the majority of the ~2,689 currently internet-facing instances.
- Apply the principle of least privilege to MCP integrations. When integrating AI/automation protocols like MCP into existing applications, treat each new endpoint as a fresh attack surface — not as an extension of the existing session model. Every endpoint needs its own explicit auth checks.
- Pin dependency versions and monitor upstream security advisories. Subscribe to the nginx-ui GitHub repository's security advisories and set up automated alerts for new releases.
- Implement Web Application Firewall (WAF) rules for
/mcpand/mcp_messagepaths, requiring session tokens and blocking unexpected request patterns. - Run regular vulnerability scans (monthly minimum) against all internet-facing services. CVE-2026-33032 was publicly known in March 2026; unpatched instances in April 2026 represent over a month of exposure.
Monitoring & Detection
Set up the following detection rules in your SIEM or log analysis platform:
Nginx access log detection — alert on POST requests to /mcp_message from non-whitelisted IPs:
# Example: grep for suspicious MCP hits in nginx access logs
grep 'POST /mcp_message' /var/log/nginx/access.log | \
awk '{print $1, $7, $9}' | \
grep -v '200\|204'
nginx-ui application log — look for configuration write events without a preceding authenticated session:
grep -E "(write_nginx_config|reload_nginx)" /var/log/nginx-ui/access.log
Network-level detection — create an IDS/IPS rule (Suricata example):
alert http any any -> $HTTP_SERVERS any (
msg:"CVE-2026-33032 nginx-ui MCP unauthenticated tool invocation attempt";
flow:established,to_server;
http.method; content:"POST";
http.uri; content:"/mcp_message"; startswith;
threshold:type limit,track by_src,count 1,seconds 60;
classtype:web-application-attack;
sid:2026033201;
rev:1;
)
Shodan/Censys monitoring — set up alerts to notify you if nginx-ui admin interfaces on your IP ranges become internet-accessible unexpectedly.
References
- CVE Entry: CVE-2026-33032 – NVD
- Original Research (Pluto Security / "MCPwn"): The Hacker News – Actively Exploited nginx-ui Flaw
- Technical Deep-Dive: Picus Security – CVE-2026-33032 Analysis
- Detection & Response: PurpleOps – Nginx Server Takeover: Detect CVE-2026-33032
- eSentire Advisory: nginx-ui Authentication Bypass Exploited
- Security Affairs Coverage: CVE-2026-33032: severe nginx-ui bug
- Patch Release: nginx-ui v2.3.4 on GitHub
- Shodan Exposure Data: Shodan – nginx ui exposed instances