May 6, 2026·7 min read·8 visits
Any authenticated user can retrieve administrative secrets (including the JWT signing key) due to flawed struct serialization, enabling total application compromise and privilege escalation.
Nginx UI versions prior to 2.3.8 suffer from an asymmetric security control enforcement vulnerability. Go's standard JSON marshaler ignores custom struct tags meant to protect sensitive configuration fields, leading to the exposure of JWT secrets, node secrets, and OIDC client credentials to any authenticated user. This allows privilege escalation to full administrator.
Nginx UI operates as a web-based management interface for Nginx web servers, providing administrators with tools to configure routing, manage certificates, and monitor server performance. The application relies on a Go-based backend providing RESTful API endpoints consumed by a frontend application. Authentication and authorization are handled via JSON Web Tokens (JWT), with specific administrative privileges required for configuration changes.
CVE-2026-42223 manifests as a CWE-200 vulnerability within the application's configuration management API. The backend exposes an endpoint designed to serve application settings to the frontend. Due to a failure in how Go struct fields are serialized into JSON, this endpoint inadvertently leaks highly sensitive cryptographic secrets to any authenticated user.
Exploitation requires a low-privileged authenticated session. Unauthenticated attackers cannot reach the vulnerable code path due to middleware enforcement. However, any user with valid credentials, regardless of their assigned role or permission boundaries, can trigger the vulnerability by interacting directly with the API.
The resulting data exposure provides the attacker with the necessary cryptographic keys to forge administrative sessions. This bypasses the application's role-based access control (RBAC) mechanisms. The severity is quantified by a CVSS 3.1 score of 6.5, reflecting the authentication prerequisite but acknowledging the high impact on confidentiality.
The vulnerability is rooted in an asymmetry between how Nginx UI processes incoming configuration changes versus how it serves outgoing configuration data. The Go backend utilizes global struct definitions to maintain application state and settings in memory. Developers attempted to secure sensitive fields within these structs by applying a custom struct tag, specifically protected:"true".
During write operations handled by the SaveSettings function, the application employs a custom function named ProtectedFill. This function uses Go's reflect package to inspect the struct tags dynamically. It identifies fields marked with protected:"true" and prevents user-supplied input from overwriting existing secrets, operating as an effective defense mechanism against unauthorized configuration tampering.
The failure occurs in the read operation handled by GetSettings located in api/settings/settings.go. To serve the settings data, the handler passes the global struct directly to the Gin web framework's c.JSON method. The Gin framework delegates this serialization to Go's standard encoding/json package. The standard library JSON marshaler only recognizes the json tag and ignores all custom tags, including protected:"true".
Because Go struct fields must be capitalized to be exported and visible to the standard library's JSON marshaler, all defined settings fields are processed. The marshaler serializes the entire struct, blindly converting the in-memory secrets into plaintext JSON values. The application's custom security annotation is rendered entirely ineffective during the read cycle.
Prior to version 2.3.8, the GetSettings function in api/settings/settings.go contained a direct passthrough of the configuration structs. The application defined sensitive fields identically to standard configuration options, relying solely on the custom tag for protection.
// Vulnerable Implementation snippet
type AppSettings struct {
JwtSecret string `json:"jwt_secret" protected:"true"`
NodeSecret string `json:"node_secret" protected:"true"`
// other fields...
}
func GetSettings(c *gin.Context) {
c.JSON(200, gin.H{
"app": cSettings.AppSettings,
// ...
})
}The patch introduced in commit 80a6a7273d43dedbd6404662893fe862a2c14bf5 addresses this by enforcing manual redaction before serialization. The developers created a constant redactedSensitiveValue and implemented a buildSettingsResponse function. This function clones the configuration memory space and explicitly overwrites known sensitive keys with the string __NGINX_UI_REDACTED__ before passing the data to c.JSON.
// Patched Implementation snippet
const redactedSensitiveValue = "__NGINX_UI_REDACTED__"
func buildSettingsResponse() gin.H {
app := cloneSettingsSection(cSettings.AppSettings)
app["jwt_secret"] = redactedSensitiveValue
app["node_secret"] = redactedSensitiveValue
// ...
return gin.H{"app": app}
}To accommodate legitimate configuration updates without corrupting existing secrets, the developers also introduced a restoreRedactedSensitiveSettings function. This function intercepts incoming save requests. If the frontend submits the exact string __NGINX_UI_REDACTED__ for a protected field, the backend discards the input and retains the original secret from memory.
While this patch mitigates CVE-2026-42223, the chosen architecture relies on a manual denylist. Developers must add new sensitive fields to the redaction function in future updates. A more robust architectural approach would involve separating the internal configuration struct from the API response struct, defining an explicit allowlist of safe fields to serialize.
Exploitation of CVE-2026-42223 is technically trivial once initial access is obtained. An attacker must first authenticate to the Nginx UI application using valid credentials. This satisfies the low-privilege prerequisite and allows the attacker's HTTP requests to bypass the initial JWT validation middleware protecting the /api routing group.
The attacker then issues an HTTP GET request to the /api/settings endpoint. No specialized headers or payloads are required. The server processes the request and returns the application's entire runtime configuration in JSON format. The attacker parses this response to locate the jwt_secret field within the app configuration block.
GET /api/settings HTTP/1.1
Host: nginx-ui.internal
Authorization: Bearer <low_privilege_token>
HTTP/1.1 200 OK
Content-Type: application/json
{
"app": {
"jwt_secret": "super_secret_hmac_key_123",
"node_secret": "cluster_node_key_456"
}
}Armed with the HMAC signing key, the attacker uses a standard JWT library to forge a new token. The payload is modified to include "role": "admin" or the equivalent highest privilege identifier used by the application. The attacker signs this forged payload using the extracted jwt_secret.
The attacker replaces their original low-privileged bearer token with the newly minted administrative token. Subsequent requests to restricted administrative endpoints are authorized by the backend, granting the attacker full control over the Nginx management interface.
The primary impact of CVE-2026-42223 is a complete compromise of the application's authorization boundary. The exposure of the JWT signing secret (JwtSecret) enables vertical privilege escalation. Any low-privileged user can elevate their access to a full administrator role, granting them the ability to modify web server routing, alter reverse proxy targets, and manage TLS certificates.
Beyond authentication bypass, the vulnerability leaks the application's cluster communication keys. The NodeSecret field is utilized to authenticate distinct instances of Nginx UI operating in a clustered environment. An attacker possessing this secret can introduce rogue nodes into the cluster hierarchy or intercept internal configuration sync traffic between legitimate nodes.
Third-party integrations are also exposed through this vulnerability. The configuration object contains the OIDC ClientSecret, which is used for single sign-on flows. Leakage of this secret compromises the OAuth trust relationship between Nginx UI and the identity provider, allowing an attacker to impersonate the application in the broader enterprise environment.
Additionally, the exposure of fields like OpenAIToken highlights the blast radius of the vulnerability. Attackers can extract these third-party API keys and utilize them outside the context of Nginx UI, incurring financial costs or quota exhaustion on the victim's external service accounts.
The vendor has addressed CVE-2026-42223 in Nginx UI version 2.3.8. Organizations running any version prior to 2.3.8 must update their deployments immediately. The patched version implements the necessary server-side redaction logic to prevent the exposure of secrets over the API while introducing a secure, 2FA-gated flow for administrators requiring access to these values.
Applying the software update does not resolve the security incident if the vulnerable endpoint was previously exposed to malicious users. Administrators must assume that all secrets contained within the application settings have been compromised. A comprehensive secret rotation process is mandatory following the application of the patch.
The JWT signing secret must be rotated immediately, which will actively invalidate all current user sessions and require users to re-authenticate. The cluster node secrets must be regenerated and redeployed across all nodes to secure inter-node communication. Furthermore, administrators must log into their external service providers to revoke and regenerate OIDC client secrets and any third-party API keys, such as OpenAI tokens.
Organizations should implement detection mechanisms by querying access logs for the affected application. Security teams should look for anomalous HTTP GET requests to the /api/settings path originating from IP addresses associated with low-privileged users. While this will not prevent exploitation, it provides necessary telemetry to identify potential compromise prior to patching.
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 ID | CWE-200 |
| Attack Vector | Network |
| CVSS Score | 6.5 |
| EPSS Score | 0.00031 |
| Impact | Privilege Escalation / Information Disclosure |
| Exploit Status | Proof of Concept |
| CISA KEV | No |
Exposure of Sensitive Information to an Unauthorized Actor