Authenticated (user role) arbitrary command execution by modifying `start_cmd` setting (GHSL-2023-268)
Description
Nginx-UI is a web interface to manage Nginx configurations. It is vulnerable to arbitrary command execution by abusing the configuration settings. The Home > Preference page exposes a list of system settings such as Run Mode, Jwt Secret, Node Secret and Terminal Start Command. While the UI doesn't allow users to modify the Terminal Start Command setting, it is possible to do so by sending a request to the API. This issue may lead to authenticated remote code execution, privilege escalation, and information disclosure. This vulnerability has been patched in version 2.0.0.beta.9.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Nginx-UI allows authenticated users to execute arbitrary commands by modifying the terminal start command setting via API, leading to RCE.
CVE-2024-22198 affects Nginx-UI, a web interface for managing Nginx configurations. The vulnerability lies in the system settings API endpoint (POST /api/settings), which allows any authenticated user to modify the Terminal Start Command setting, even though the UI does not expose this field for editing. The start_cmd value is used when spawning a terminal via the web interface, leading to arbitrary command execution. [2][3]
To exploit, an attacker must have a valid user account (any authenticated user role). By sending a crafted request to the settings API with a malicious start_cmd value, the attacker replaces the legitimate command. Once the terminal feature is triggered, the system executes the attacker-controlled command with the privileges of the Nginx-UI process. [3]
Successful exploitation results in authenticated remote code execution, which can lead to privilege escalation and information disclosure. The attacker gains the ability to run arbitrary commands on the server, potentially compromising the entire host. [2]
This vulnerability is patched in version 2.0.0.beta.9. The fix adds a fillSettings function that uses reflection to omit protected fields during settings binding, preventing modification of sensitive settings like start_cmd. Users are advised to upgrade to the patched version immediately. [4]
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/0xJacky/Nginx-UIGo | < 2.0.0.beta.9 | 2.0.0.beta.9 |
Affected products
2- 0xJacky/nginx-uiv5Range: < 2.0.0.beta.9
Patches
1827e76c46e63fix: add protected fields to settings to mitigate high-severity vulnerability
3 files changed · +61 −46
api/system/settings.go+46 −31 modified@@ -1,42 +1,57 @@ package system import ( - "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/settings" - "github.com/gin-gonic/gin" - "net/http" + "github.com/0xJacky/Nginx-UI/api" + "github.com/0xJacky/Nginx-UI/settings" + "github.com/gin-gonic/gin" + "net/http" + "reflect" ) func GetSettings(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "server": settings.ServerSettings, - "nginx": settings.NginxSettings, - "openai": settings.OpenAISettings, - }) + c.JSON(http.StatusOK, gin.H{ + "server": settings.ServerSettings, + "nginx": settings.NginxSettings, + "openai": settings.OpenAISettings, + }) } func SaveSettings(c *gin.Context) { - var json struct { - Server settings.Server `json:"server"` - Nginx settings.Nginx `json:"nginx"` - Openai settings.OpenAI `json:"openai"` - } - - if !api.BindAndValid(c, &json) { - return - } - - settings.ServerSettings = json.Server - settings.NginxSettings = json.Nginx - settings.OpenAISettings = json.Openai - - settings.ReflectFrom() - - err := settings.Save() - if err != nil { - api.ErrHandler(c, err) - return - } + var json struct { + Server settings.Server `json:"server"` + Nginx settings.Nginx `json:"nginx"` + Openai settings.OpenAI `json:"openai"` + } + + if !api.BindAndValid(c, &json) { + return + } + + // todo: omit protected fields when binding + fillSettings(&settings.ServerSettings, &json.Server) + fillSettings(&settings.NginxSettings, &json.Nginx) + fillSettings(&settings.OpenAISettings, &json.Openai) + + settings.ReflectFrom() + + err := settings.Save() + if err != nil { + api.ErrHandler(c, err) + return + } + + GetSettings(c) +} - GetSettings(c) +func fillSettings(targetSettings interface{}, newSettings interface{}) { + s := reflect.TypeOf(targetSettings).Elem() + vt := reflect.ValueOf(targetSettings).Elem() + vn := reflect.ValueOf(newSettings).Elem() + + // copy the values from new to target settings if it is not protected + for i := 0; i < s.NumField(); i++ { + if s.Field(i).Tag.Get("protected") != "true" { + vt.Field(i).Set(vn.Field(i)) + } + } }
settings/nginx.go+5 −5 modified@@ -3,11 +3,11 @@ package settings type Nginx struct { AccessLogPath string `json:"access_log_path"` ErrorLogPath string `json:"error_log_path"` - ConfigDir string `json:"config_dir"` - PIDPath string `json:"pid_path"` - TestConfigCmd string `json:"test_config_cmd"` - ReloadCmd string `json:"reload_cmd"` - RestartCmd string `json:"restart_cmd"` + ConfigDir string `json:"config_dir" protected:"true"` + PIDPath string `json:"pid_path" protected:"true"` + TestConfigCmd string `json:"test_config_cmd" protected:"true"` + ReloadCmd string `json:"reload_cmd" protected:"true"` + RestartCmd string `json:"restart_cmd" protected:"true"` } var NginxSettings = Nginx{
settings/server.go+10 −10 modified@@ -1,18 +1,18 @@ package settings type Server struct { - HttpHost string `json:"http_host"` - HttpPort string `json:"http_port"` - RunMode string `json:"run_mode"` - JwtSecret string `json:"jwt_secret"` - NodeSecret string `json:"node_secret"` + HttpHost string `json:"http_host" protected:"true"` + HttpPort string `json:"http_port" protected:"true"` + RunMode string `json:"run_mode" protected:"true"` + JwtSecret string `json:"jwt_secret" protected:"true"` + NodeSecret string `json:"node_secret" protected:"true"` HTTPChallengePort string `json:"http_challenge_port"` - Email string `json:"email"` - Database string `json:"database"` - StartCmd string `json:"start_cmd"` + Email string `json:"email" protected:"true"` + Database string `json:"database" protected:"true"` + StartCmd string `json:"start_cmd" protected:"true"` CADir string `json:"ca_dir"` - Demo bool `json:"demo"` - PageSize int `json:"page_size"` + Demo bool `json:"demo" protected:"true"` + PageSize int `json:"page_size" protected:"true"` GithubProxy string `json:"github_proxy"` }
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
9- github.com/advisories/GHSA-8r25-68wm-jw35ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-22198ghsaADVISORY
- github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/api/system/settings.goghsax_refsource_MISCWEB
- github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/api/terminal/pty.goghsax_refsource_MISCWEB
- github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/internal/pty/pipeline.goghsax_refsource_MISCWEB
- github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/router/middleware.goghsax_refsource_MISCWEB
- github.com/0xJacky/nginx-ui/blob/04bf8ec487f06ab17a9fb7f34a28766e5f53885e/settings/server.goghsax_refsource_MISCWEB
- github.com/0xJacky/nginx-ui/commit/827e76c46e63c52114a62a899f61313039c754e3ghsax_refsource_MISCWEB
- github.com/0xJacky/nginx-ui/security/advisories/GHSA-8r25-68wm-jw35ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.