VYPR
High severityNVD Advisory· Published Jan 11, 2024· Updated Aug 1, 2024

Authenticated (user role) arbitrary command execution by modifying `start_cmd` setting (GHSL-2023-268)

CVE-2024-22198

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.

PackageAffected versionsPatched versions
github.com/0xJacky/Nginx-UIGo
< 2.0.0.beta.92.0.0.beta.9

Affected products

2

Patches

1
827e76c46e63

fix: add protected fields to settings to mitigate high-severity vulnerability

https://github.com/0xJacky/nginx-uiHintayDec 19, 2023via ghsa
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

News mentions

0

No linked articles in our index yet.