May 5, 2026·7 min read·10 visits
Low-privileged authenticated users can retrieve the system's `node.secret` via the `/api/settings` endpoint. This secret can then be passed in the `X-Node-Secret` header to execute actions as the administrative init user.
An information disclosure vulnerability in Nginx UI prior to version 2.3.8 allows authenticated users to extract the internal node secret. This secret can subsequently be abused to bypass authorization checks and escalate privileges to the administrative init user.
Nginx UI is a web-based administration interface designed to manage Nginx web server configurations. The application utilizes a role-based access control system to differentiate between standard users and administrative accounts. Standard users possess limited read access, while administrative accounts maintain full control over system state and configuration files.
The vulnerability, tracked as CVE-2026-42220, represents a critical intersection of an information disclosure flaw (CWE-200) and an authorization bypass mechanism (CWE-863). The issue resides in how the application exposes internal configuration states to standard users. Exploitation requires an attacker to possess valid credentials for a low-privileged account within the Nginx UI environment.
At the core of the issue is the /api/settings endpoint, which is accessible to any authenticated user. This endpoint fails to adequately redact sensitive internal variables before serializing the system configuration to JSON. Specifically, the endpoint leaks the node.secret variable in plaintext.
The resulting impact is absolute privilege escalation. The leaked secret serves as a pre-shared key for internal node communication. By supplying this leaked key back to the application via specific HTTP headers, an attacker authenticates as the primary administrative account, effectively taking full control of the Nginx UI instance.
The fundamental root cause originates in the GetSettings handler located within api/settings/settings.go. When a client initiates a GET request to the /api/settings endpoint, the application retrieves the NodeSettings and AppSettings structs directly from memory. These structs contain multiple sensitive operational fields, including node.secret and app.jwt_secret.
The developers attempted to secure these fields using custom struct tags intended to mark them as protected. The standard Go JSON marshaler does not natively interpret these custom security tags. Consequently, the serialization process outputs the entire struct, including the highly sensitive internal secrets, directly into the HTTP response body without any redaction.
The second component of the vulnerability resides in the AuthRequired middleware within internal/middleware/middleware.go. This middleware facilitates automated node-to-node communication by accepting the node.secret value via the X-Node-Secret HTTP header or the node_secret query parameter. It is designed to bypass standard JWT validation when a valid node secret is provided.
When the middleware verifies the provided node secret against the internal configuration, it automatically associates the inbound request with the init user. The init user represents the system's primary administrator. Because the application explicitly leaks the exact secret required by this middleware, the authorization model completely collapses.
The unpatched implementation of the settings API endpoint fetches the application configuration and serializes it indiscriminately. The JSON response directly mirrors the internal struct memory layout. The standard library function json.Marshal() ignores custom tags unless explicitly implemented via a custom MarshalJSON method.
To resolve this, the patch introduced in commit 80a6a7273d43dedbd6404662893fe862a2c14bf5 implements a hardcoded redaction layer. A constant named __NGINX_UI_REDACTED__ is now used to mask sensitive values before serialization occurs. The endpoint scrubs specific fields, including jwt_secret, node.secret, and openai.token.
// Pseudo-code representation of the patched serialization logic
func GetSettings(c *gin.Context) {
settings := config.GetNodeSettings()
// Redaction applied prior to output
settings.NodeSecret = "__NGINX_UI_REDACTED__"
settings.JwtSecret = "__NGINX_UI_REDACTED__"
c.JSON(http.StatusOK, settings)
}To support legitimate administrative tasks that require viewing these secrets, the patch introduces a new endpoint at GET /api/settings/protected. This endpoint is secured behind the RequireSecureSession() middleware. This new middleware mandates a valid, human-interactive session.
Crucially, the RequireSecureSession() middleware actively rejects requests that authenticated via the X-Node-Secret header. This prevents a scenario where an attacker uses a partially leaked secret or legacy node access to query the protected endpoint, effectively closing the circular privilege escalation loop.
Exploitation requires network reachability to the Nginx UI management interface and a valid JSON Web Token (JWT) belonging to a low-privileged user. The attacker initiates the exploitation sequence by querying the operational settings of the application. The objective is to extract the administrative node secret from the JSON payload.
curl -X GET http://<nginx-ui-host>/api/settings -H "Authorization: Bearer <user_jwt>"The server returns a JSON response containing the plaintext configuration variables. The attacker parses this output to locate the node.secret key. Once obtained, the attacker constructs a subsequent request targeting an administrative endpoint, replacing the standard authorization header with the X-Node-Secret header.
curl -X GET http://<nginx-ui-host>/api/backup -H "X-Node-Secret: <leaked_node_secret>"In this example, the attacker targets the /api/backup endpoint. The middleware verifies the injected header, associates the request with the init user, and executes the backup procedure. The response from this endpoint contains the raw backup archive.
Furthermore, the application exposes encryption metadata directly in the backup response. The X-Backup-Security HTTP header contains the AES encryption key and Initialization Vector (IV) used to secure the backup archive. The attacker utilizes this metadata to immediately decrypt the exfiltrated configuration files, obtaining SSL certificates and database credentials.
The successful execution of this attack path results in a complete compromise of the Nginx UI access control model. By obtaining the init user context, the attacker assumes administrative control over the management interface. This access permits the modification of internal application settings, user management, and core Nginx web server configurations.
The ability to interact with the backup and restore endpoints introduces severe confidentiality and integrity risks. The exfiltration of the backup archive, combined with the disclosure of the AES decryption key in the response headers, exposes all underlying cryptographic assets managed by the system. Conversely, the restore functionality allows an attacker to overwrite the current system state with a malicious configuration.
The National Vulnerability Database assigns a CVSS v3.1 base score of 6.5 (Medium), emphasizing the high confidentiality impact. However, alternative assessments by IBM X-Force assign a score of 7.5 (High), noting that the subsequent administrative escalation implicitly facilitates severe integrity and availability consequences. The vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N correctly describes the initial information disclosure, but underrepresents the ultimate systemic impact.
The Exploit Prediction Scoring System (EPSS) yields a score of 0.00028, placing the vulnerability in the 7.93rd percentile. This extremely low probability score indicates an absence of observed mass exploitation in the wild. Despite this low score, the existence of public proof-of-concept methodologies makes targeted attacks highly viable.
Organizations utilizing Nginx UI must upgrade immediately to version 2.3.8 or later. The patch implements the __NGINX_UI_REDACTED__ constant and enforces strict session verification logic on the new /api/settings/protected endpoint. These code-level changes definitively close the information disclosure sink and prevent the circular authorization bypass.
Applying the software update does not resolve the threat for environments where the node.secret or app.jwt_secret has already been exposed. The update mitigates future disclosures but does not invalidate existing secrets. Administrators must manually force a secret rotation to ensure that previously extracted keys cannot be used for administrative access.
To rotate the secrets, administrators must manually edit the app.ini configuration file residing on the Nginx UI host filesystem. The node.secret and app.jwt_secret variables must be replaced with newly generated, cryptographically secure random strings. Following these modifications, the Nginx UI service must be restarted to load the new credentials into memory.
Version 2.3.8 also modifies the initial deployment and restoration procedures. The application now requires the presence of a transient .install_secret file on the local filesystem during the setup phase. This architectural change eliminates reliance on static credentials for initial administrative bootstrapping, reducing the attack surface during deployment.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
nginx-ui 0xJacky | < 2.3.8 | 2.3.8 |
| Attribute | Detail |
|---|---|
| CWE IDs | CWE-200, CWE-863 |
| Attack Vector | Network |
| Authentication | Required (Low Privilege) |
| CVSS Score | 6.5 / 7.5 |
| EPSS Score | 0.00028 |
| Exploit Status | Public PoC |
| Impact | Privilege Escalation |
Exposure of Sensitive Information to an Unauthorized Actor