Apr 21, 2026·7 min read·5 visits
A flaw in Nginx UI (< 2.3.4) allows disabled users to retain access using unexpired JWTs. The system fails to check user account status during API request validation, enabling privilege escalation and persistence.
Nginx UI versions prior to 2.3.4 contain an improper access control vulnerability resulting from incomplete JSON Web Token (JWT) validation. The application verifies the cryptographic signature and expiration of API tokens but fails to perform a stateful check against the underlying user database to confirm the account remains active. An attacker with a previously issued JWT can maintain full administrative access to the Nginx UI management interface even after their account is disabled by an administrator.
Nginx UI serves as an administrative front-end for managing Nginx web server configurations. It exposes a comprehensive REST API that allows users to modify routing rules, manage TLS certificates, and configure access controls. Authentication for this API is implemented using JSON Web Tokens (JWT), which are issued upon successful credential verification during the initial login phase.
The core vulnerability resides in the discrepancy between the application's authentication issuance and its subsequent request validation logic. While the login endpoint correctly queries the database to ensure the user account is active, the middleware responsible for securing subsequent API calls relies exclusively on the stateless properties of the JWT. The application validates the token's cryptographic signature and time-to-live (TTL) but does not query the user directory to verify the account's current status.
This architectural oversight leads to a state synchronization failure between the authorization mechanism and the identity provider database. If an administrator disables a user account, the restriction is recorded in the database but is not propagated to the active session validation flow. The affected user retains full access to the API for the remainder of the token's validity period, resulting in an Improper Access Control (CWE-284) and Incorrect Authorization (CWE-863) condition.
The following diagram illustrates the flawed authorization flow:
The root cause of CVE-2026-33031 is the implementation of stateless authentication in an environment that requires stateful authorization guarantees. When a user authenticates, the system validates their credentials, checks the user.Status boolean field, and generates a signed JWT containing a user_id claim. This token is then returned to the client to be used as a Bearer token in the Authorization header for all future requests.
In vulnerable versions of Nginx UI, the request validation middleware processes the incoming JWT using a standard cryptographic verification library. If the signature matches the server's private key and the exp (expiration) claim is in the future, the middleware explicitly trusts the user_id embedded within the payload. The execution flow directly proceeds to the requested API endpoint controller without querying the database to determine if the user.Status field has changed since the token was issued.
This behavior violates the principle of complete mediation, which dictates that every access to every object must be checked for authority. By treating the JWT as an immutable proof of both authentication and authorization, the system assumes that user privileges are static for the duration of the token's life. The failure to cross-reference the user_id claim with the current database state creates a time-of-check to time-of-use (TOCTOU) race condition that spans the entire validity period of the JWT.
The vulnerability was remediated in version 2.3.4 via commit 7b66578adb47bbec839b621a4666495249379174. The vendor addressed the flaw by introducing stateful verification mechanisms within the request lifecycle and implementing an event-driven session revocation system. These changes bridge the gap between the stateless JWT and the stateful database.
The core of the fix involves the introduction of a new helper function, getActiveUserByID, located in internal/user/user.go. This function is invoked during the middleware evaluation phase. Instead of blindly trusting the JWT payload, the application now retrieves the user object corresponding to the user_id claim from either a synchronized cache or the primary database. The system explicitly verifies that the user.Status field evaluates to true before permitting the request to proceed to the designated API controller.
To manage performance overhead and ensure cache coherence, the patch introduces an ExecutedHook in api/user/user.go. This hook monitors administrative endpoints for modifications to the status and password fields. When an administrator disables a user account, the hook triggers the newly implemented DeleteUserTokens function. This function executes two critical operations: it deletes all active session records associated with the user from the auth_tokens database table, and it immediately purges the corresponding user object from the application's memory cache.
This multi-layered approach ensures comprehensive remediation. The proactive revocation mechanism (DeleteUserTokens) handles immediate session termination upon administrative action, while the reactive validation mechanism (getActiveUserByID) ensures that no token can successfully authenticate against a disabled account, regardless of the system's cache state or session table integrity.
Exploitation of this vulnerability requires an attacker to possess a valid JWT issued before the administrative revocation of their account. The attack begins with standard interaction: the user authenticates with valid credentials, and the server issues a JWT. At a subsequent point, an administrator identifies the user as malicious or compromised and disables the account via the Nginx UI management console.
The attacker bypasses the administrative restriction by continuing to submit the previously acquired JWT in the Authorization header of their HTTP requests. Because the server only checks the token's signature and expiration, the API accepts the request and executes the corresponding action. The attacker retains their original privilege level, which in the context of Nginx UI, typically includes administrative control over web server configurations.
To achieve persistence beyond the expiration of the captured JWT, the attacker leverages their retained access to provision secondary authentication mechanisms. The attacker sends a POST request to the user creation API endpoint to register a new, fully active administrative account. When the original JWT expires, the attacker switches to the newly provisioned credentials, permanently bypassing the original account restriction and securing long-term access to the system.
CVE-2026-33031 carries a CVSS 4.0 score of 8.6, reflecting a high severity impact on both confidentiality and integrity. The vulnerability allows an unauthorized entity to maintain administrative control over the Nginx UI application, which translates directly to control over the underlying Nginx web server infrastructure. This control extends to routing rules, upstream server definitions, and access control lists.
An attacker exploiting this flaw can modify Nginx configurations to intercept plaintext HTTP traffic, alter response payloads, or redirect requests to infrastructure under their control. Furthermore, the attacker can manipulate TLS certificates managed by Nginx UI, potentially facilitating man-in-the-middle (MitM) attacks or compromising the cryptographic integrity of hosted web services. The ability to exfiltrate database credentials or internal API keys defined within the Nginx configuration further expands the blast radius.
The specific persistence vector associated with this vulnerability elevates the overall risk. Because the compromised account retains the ability to create new user identities, the attacker can silently establish multiple backdoors within the Nginx UI database. Security teams relying on account deactivation as an incident response measure will falsely believe the threat is contained, while the attacker continues operating through newly provisioned, active accounts.
The primary and most effective remediation for CVE-2026-33031 is upgrading the Nginx UI deployment to version 2.3.4 or later. This version incorporates the architectural changes necessary to enforce stateful authorization checks and manage session revocation. System administrators should apply this update immediately, especially in environments exposed to untrusted networks or where multiple users share administrative access.
In environments where patching cannot be executed immediately, administrators must implement a temporary mitigation strategy to handle compromised or disabled accounts. The only mechanism to force-logout a disabled user in vulnerable versions is to invalidate the cryptographic material used to sign the JWTs. Administrators must rotate the JwtSecret parameter in the Nginx UI configuration file and restart the application service.
Rotating the JwtSecret instantly renders all previously issued tokens invalid, as their signatures will no longer match the server's expected value. This action forces all active users to re-authenticate. While this results in a global session disruption, it successfully severs access for disabled accounts. Additionally, security teams should conduct a thorough audit of the Nginx UI user database to identify and remove any unauthorized accounts created during the window of vulnerability.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Nginx UI 0xJacky | < 2.3.4 | 2.3.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-284, CWE-863 |
| Attack Vector | Network |
| CVSS 4.0 Score | 8.6 |
| Impact | High Confidentiality, High Integrity (Privilege Escalation) |
| EPSS Percentile | 11.57% |
| Exploit Status | None (No public PoC) |
| CISA KEV | Not Listed |
Improper Access Control / Incorrect Authorization