CVE-2024-22197: Nginx-UI: authenticated command injection to RCE

GHSA-pxmr-q2x3-9x9m HIGH
Published January 11, 2024
CISO Take

Nginx-UI, a web management panel for nginx, exposes hidden settings (test_config_cmd, reload_cmd, restart_cmd) through its /api/settings endpoint that the UI hides but the API happily accepts from any authenticated user, with no role check separating a brand-new self-registered account from an admin. Because those commands are later executed via /bin/sh -c whenever nginx config is tested or reloaded (e.g. when adding a site), any logged-in user can plant a shell command and get it executed as the nginx-ui process user, typically root in containerized deployments — full RCE, privilege escalation, and information disclosure, rated CVSS 7.7. There's no CISA KEV listing, no public exploit or Nuclei template, and EPSS sits at 0.015 (top 28th percentile) — so this isn't being mass-exploited today, but a working, copy-paste PoC is public in the GitHub advisory and the flaw touches 4,631 downstream dependents, so opportunistic weaponization is plausible. Nginx-UI is frequently deployed to front self-hosted AI/LLM infrastructure (model-serving endpoints, LLM API gateways) and even ships its own OpenAI proxy/token settings field, so a compromised instance can leak those AI API keys alongside full host takeover. Action: upgrade to the patched commit (≥1.9.10-0.20231219184941-827e76c46e63), disable open self-registration or restrict nginx-ui access to trusted admins only, and rotate any API keys stored in its settings.

Sources: NVD GitHub Advisory EPSS CISA KEV ATLAS

What is the risk?

High severity in practice despite moderate EPSS: the flaw requires only a low-privileged authenticated account (no special access, no user interaction beyond a normal workflow step), the injection point is unsanitized shell concatenation, and a working PoC is publicly documented in the GHSA advisory. The main limiting factor is that exploitation requires network/API access to an nginx-ui instance and an account on it — internet-facing, open-registration deployments (common in self-hosted homelab/AI-infra setups) are at meaningfully higher risk than internal, access-controlled ones. Not in CISA KEV and no scanner template yet, so current in-the-wild exploitation is unconfirmed, but the low complexity of weaponizing this once discovered by opportunistic scanners warrants prompt patching rather than a wait-and-see approach.

How does the attack unfold?

Initial access
Adversary obtains or self-registers a low-privileged nginx-ui account and authenticates, since the platform lacks role-based authorization on settings changes.
AML.T0012
Malicious settings injection
Attacker POSTs to /api/settings, overwriting test_config_cmd/reload_cmd/restart_cmd with an OS command payload.
AML.T0050
Trigger execution
Attacker performs a routine action (e.g., adding a new nginx site) that causes nginx-ui to invoke the poisoned command via /bin/sh -c.
AML.T0050
Impact: RCE and credential exposure
Attacker gains a shell as the nginx-ui process user (often root), enabling host compromise, exfiltration of stored credentials including any configured LLM/OpenAI API keys, and lateral movement to co-located AI services.
AML.T0025

What systems are affected?

Package Ecosystem Vulnerable Range Patched
OpenAI Node go < 1.9.10-0.20231219184941-827e76c46e63 1.9.10-0.20231219184941-827e76c46e63
11.1K 311 dependents Pushed 5d ago 62% patched ~338d to patch Full package profile →

Do you use OpenAI Node? You're affected.

How severe is it?

CVSS 3.1
7.7 / 10
EPSS
1.5%
chance of exploitation in 30 days
Higher than 73% of all CVEs
Exploitation Status
No known exploitation
Sophistication
Trivial

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC High
PR None
UI None
S Unchanged
C High
I High
A Low

What should I do?

1 step
  1. 1) Patch: upgrade nginx-ui to a build including commit 827e76c46e63 (≥1.9.10-0.20231219184941-827e76c46e63) or the latest release. 2) Compensating control if patching is delayed: disable open self-registration, restrict nginx-ui login to trusted admin accounts only, and place the instance behind network-level access controls (VPN/IP allowlist) so untrusted users cannot reach /api/settings. 3) Rotate any credentials stored in nginx-ui settings, including OpenAI/LLM API tokens, since they may have been exposed even without the command-injection step being exercised. 4) Detection: alert on POST requests to /api/settings containing shell metacharacters (;, |, &&, $()) in the nginx fields, and monitor for unexpected child processes of the nginx-ui binary invoking /bin/sh -c. 5) Diff current test_config_cmd/reload_cmd/restart_cmd values against known-good (empty/default) baselines.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

NIST AI RMF
GOVERN 6.1 - Policies and procedures are in place to address AI risks associated with third-party components
OWASP LLM Top 10
LLM03 - Supply Chain Vulnerabilities

Frequently Asked Questions

What is CVE-2024-22197?

Nginx-UI, a web management panel for nginx, exposes hidden settings (test_config_cmd, reload_cmd, restart_cmd) through its /api/settings endpoint that the UI hides but the API happily accepts from any authenticated user, with no role check separating a brand-new self-registered account from an admin. Because those commands are later executed via /bin/sh -c whenever nginx config is tested or reloaded (e.g. when adding a site), any logged-in user can plant a shell command and get it executed as the nginx-ui process user, typically root in containerized deployments — full RCE, privilege escalation, and information disclosure, rated CVSS 7.7. There's no CISA KEV listing, no public exploit or Nuclei template, and EPSS sits at 0.015 (top 28th percentile) — so this isn't being mass-exploited today, but a working, copy-paste PoC is public in the GitHub advisory and the flaw touches 4,631 downstream dependents, so opportunistic weaponization is plausible. Nginx-UI is frequently deployed to front self-hosted AI/LLM infrastructure (model-serving endpoints, LLM API gateways) and even ships its own OpenAI proxy/token settings field, so a compromised instance can leak those AI API keys alongside full host takeover. Action: upgrade to the patched commit (≥1.9.10-0.20231219184941-827e76c46e63), disable open self-registration or restrict nginx-ui access to trusted admins only, and rotate any API keys stored in its settings.

Is CVE-2024-22197 actively exploited?

No confirmed active exploitation of CVE-2024-22197 has been reported, but organizations should still patch proactively.

How to fix CVE-2024-22197?

1) Patch: upgrade nginx-ui to a build including commit 827e76c46e63 (≥1.9.10-0.20231219184941-827e76c46e63) or the latest release. 2) Compensating control if patching is delayed: disable open self-registration, restrict nginx-ui login to trusted admin accounts only, and place the instance behind network-level access controls (VPN/IP allowlist) so untrusted users cannot reach /api/settings. 3) Rotate any credentials stored in nginx-ui settings, including OpenAI/LLM API tokens, since they may have been exposed even without the command-injection step being exercised. 4) Detection: alert on POST requests to /api/settings containing shell metacharacters (;, |, &&, $()) in the nginx fields, and monitor for unexpected child processes of the nginx-ui binary invoking /bin/sh -c. 5) Diff current test_config_cmd/reload_cmd/restart_cmd values against known-good (empty/default) baselines.

What systems are affected by CVE-2024-22197?

This vulnerability affects the following AI/ML architecture patterns: model serving, LLM API gateways.

What is the CVSS score for CVE-2024-22197?

CVE-2024-22197 has a CVSS v3.1 base score of 7.7 (HIGH). The EPSS exploitation probability is 1.54%.

What is the AI security impact?

Affected AI Architectures

model servingLLM API gateways

MITRE ATLAS Techniques

AML.T0012 Valid Accounts
AML.T0049 Exploit Public-Facing Application
AML.T0050 Command and Scripting Interpreter

Compliance Controls Affected

NIST AI RMF: GOVERN 6.1
OWASP LLM Top 10: LLM03

What are the technical details?

Original Advisory

### Summary The `Home > Preference` page exposes a small list of nginx settings such as `Nginx Access Log Path` and `Nginx Error Log Path`. However, the API also exposes `test_config_cmd`, `reload_cmd` and `restart_cmd`. While the UI doesn't allow users to modify any of these settings, it is possible to do so by sending a request to the [API](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/api/system/router.go#L13). ```go func InitPrivateRouter(r *gin.RouterGroup) { r.GET("settings", GetSettings) r.POST("settings", SaveSettings) ... } ``` The [`SaveSettings`](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/api/system/settings.go#L18) function is used to save the settings. It is protected by the [`authRequired`](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/router/middleware.go#L45) middleware, which requires a valid JWT token or a `X-Node-Secret` which must equal the `Node Secret` configuration value. However, given the lack of authorization roles, any authenticated user can modify the settings. The `SaveSettings` function is defined as follows: ```go func SaveSettings(c *gin.Context) { var json struct { ... Nginx settings.Nginx `json:"nginx"` ... } ... settings.NginxSettings = json.Nginx ... err := settings.Save() ... } ``` The `test_config_cmd` setting is stored as [`settings.NginxSettings.TestConfigCmd`](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/settings/nginx.go#L8). When the application wants to test the nginx configuration, it uses the [`TestConf`](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/internal/nginx/nginx.go#L26) function: ```go func TestConf() (out string) { if settings.NginxSettings.TestConfigCmd != "" { out = execShell(settings.NginxSettings.TestConfigCmd) return } out = execCommand("nginx", "-t") return } ``` The [`execShell`](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/internal/nginx/nginx.go#L8) function is defined as follows: ```go func execShell(cmd string) (out string) { bytes, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() out = string(bytes) if err != nil { out += " " + err.Error() } return } ``` Where the `cmd` argument is user-controlled and is passed to `/bin/sh -c`. This issue was found using CodeQL for Go: [Command built from user-controlled sources](https://codeql.github.com/codeql-query-help/go/go-command-injection/). #### Proof of Concept > Based on [this setup](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/README.md?plain=1#L210) using `uozi/nginx-ui:v2.0.0-beta.7`. 1. Login as a newly created user. 2. Send the following request to modify the settings with `"test_config_cmd":"touch /tmp/pwned"`. ```http POST /api/settings HTTP/1.1 Host: 127.0.0.1:8080 Content-Length: 528 Authorization: <<JWT TOKEN> Content-Type: application/json {"nginx":{"access_log_path":"","error_log_path":"","config_dir":"","pid_path":"","test_config_cmd":"touch /tmp/pwned","reload_cmd":"","restart_cmd":""},"openai":{"base_url":"","token":"","proxy":"","model":""},"server":{"http_host":"0.0.0.0","http_port":"9000","run_mode":"debug","jwt_secret":"foo","node_secret":"foo","http_challenge_port":"9180","email":"foo","database":"foo","start_cmd":"","ca_dir":"","demo":false,"page_size":10,"github_proxy":""}} ``` 3. Add a new site in `Home > Manage Sites > Add Site` with random data. The previously-modified `test_config_cmd` setting will be used [when the application tries to test the nginx configuration](https://github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/api/sites/domain.go#L256). 4. Verify that `/tmp/pwned` exists. ``` $ docker exec -it $(docker ps -q) ls -al /tmp -rw-r--r-- 1 root root 0 Dec 14 21:10 pwned ``` ### Impact This issue may lead to authenticated Remote Code Execution, Privilege Escalation, and Information Disclosure.

Exploitation Scenario

An adversary obtains or self-registers a low-privileged account on an internet-facing nginx-ui instance used to manage the reverse proxy in front of a self-hosted LLM/AI stack. After authenticating, they send a POST to /api/settings setting test_config_cmd to a reverse-shell one-liner. They then perform a routine, permitted action — adding or editing a site through the normal UI — which server-side triggers nginx-ui's TestConf() function, invoking the attacker-controlled command via execShell()/bin/sh -c. This returns a shell running as the nginx-ui process user (often root in Docker deployments), from which the attacker can read environment variables and configuration secrets (including any LLM/OpenAI API keys configured in nginx-ui), pivot laterally into co-located model-serving or vector-DB containers, or rewrite the nginx configuration to intercept and manipulate AI inference traffic passing through the proxy.

Weaknesses (CWE)

CWE-77 — Improper Neutralization of Special Elements used in a Command ('Command Injection'): The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.

  • [Architecture and Design] If at all possible, use library calls rather than external processes to recreate the desired functionality.
  • [Implementation] If possible, ensure that all external commands called from the program are statically created.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:L

Timeline

Published
January 11, 2024
Last Modified
July 6, 2026
First Seen
July 6, 2026

Related Vulnerabilities