Oct 10, 2026·5 min read·4 visits
Unconfigured trusted reverse proxies in Nginx UI cause client IP misattribution to loopback, allowing IP white-list bypass and authentication lockout DoS.
Nginx UI versions 2.2.0 through 2.5.10 fail to properly configure Gin framework trusted proxies when deployed behind a reverse proxy. This causes all incoming HTTP requests to be attributed to the loopback IP (127.0.0.1), enabling IP allowlist bypass and global authentication lockouts.
CVE-2026-107804 represents an origin validation flaw in Nginx UI, a web interface for managing Nginx web server configurations. The backend application, written in Go using the Gin web framework, fails to properly establish trusted proxy boundaries. Affected versions span from 2.2.0 up to, but excluding, 2.6.0.
In standard deployments, Nginx UI runs behind a local Nginx reverse proxy instance that forwards HTTP requests to the Go application listening on local port 9000. Because the Gin backend is not explicitly configured with trusted proxy addresses via SetTrustedProxies, client IP address extraction defaults to the socket connection peer address (127.0.0.1).
This misattribution results in two severe operational impacts. First, requests routed through the local proxy bypass configured administrative IP allowlists. Second, failed authentication attempts across disparate external clients aggregate under the single loopback IP, enabling unauthenticated remote attackers to trigger account lockouts.
The root cause of CVE-2026-107804 stems from Gin's client IP resolution mechanics combined with missing framework initialization. Gin determines client IP addresses via c.ClientIP(). When trusted proxies are undefined, Gin ignores forwarded request headers (X-Forwarded-For or X-Real-IP) to prevent IP spoofing from untrusted network clients.
Because the backend framework leaves the trusted proxy list empty, Gin relies exclusively on the TCP socket remote peer address (c.Request.RemoteAddr). In the default architecture, Nginx UI routes incoming external connections through a local Nginx proxy peer. Consequently, every request entering the Go application appears to originate directly from 127.0.0.1 or ::1.
This flaw cascades into security-critical application logic. The IPWhiteList() middleware permits requests if c.ClientIP() matches 127.0.0.1 to prevent local admin lockout. Similarly, the BanIP table in SQLite/GORM indexes failed logins by c.ClientIP(), grouping all external client failures under 127.0.0.1.
In affected versions (2.2.0 through 2.5.10), the application router initialization in router/routers.go failed to invoke engine.SetTrustedProxies(). As a result, the default empty proxy configuration caused c.ClientIP() to resolve to the peer address of the reverse proxy.
The official fix in commit e30e331303fc21cf077a2bea724bd79e66892eaf introduces trusted proxy configuration directly into the router startup path. The fix defines proxy evaluation logic in router/client_ip.go and updates configuration binding structures.
// Vulnerable Code Path (Pre-2.6.0): router/routers.go
// Engine initialized without setting trusted proxy boundaries
r := gin.Default()
// c.ClientIP() falls back to TCP connection RemoteAddr (127.0.0.1)
// Patched Implementation: router/client_ip.go in commit e30e331303fc21cf077a2bea724bd79e66892eaf
var bundledNginxTrustedProxies = []string{"127.0.0.1", "::1"}
func trustedProxiesForCurrentTopology() []string {
trustedProxies := slices.Clone(settings.AuthSettings.TrustedProxies)
if !helper.ShouldManageBundledNginx() {
return trustedProxies
}
for _, trustedProxy := range bundledNginxTrustedProxies {
if !slices.Contains(trustedProxies, trustedProxy) {
trustedProxies = append(trustedProxies, trustedProxy)
}
}
return trustedProxies
}
func configureTrustedProxies(engine *gin.Engine) error {
// Formally registers trusted proxy addresses with the Gin engine
return engine.SetTrustedProxies(trustedProxiesForCurrentTopology())
}By executing SetTrustedProxies during router setup, Gin safely parses X-Forwarded-For headers sent by the trusted proxy while continuing to reject unvalidated headers from untrusted connections.
Exploitation of CVE-2026-107804 requires network connectivity to an Nginx UI instance deployed behind a reverse proxy. Attackers can leverage this misconfiguration to achieve two primary outcomes without requiring prior authentication.
To bypass IP allowlist controls, an attacker issues administrative API requests to Nginx UI via the web interface. Because the backend evaluates the request source as 127.0.0.1, the IPWhiteList() middleware grants access past the network restriction layer. Valid user credentials remain necessary to access protected endpoints.
To execute a Denial of Service, an attacker submits intentional bad authentication requests (such as invalid passwords or incorrect OTP codes) to the login endpoint. Each failure increments the counter for 127.0.0.1 in the database. When the count exceeds MaxAttempts within BanThresholdMinutes, Nginx UI issues a global lockout on 127.0.0.1, preventing legitimate users from logging into the management interface.
CVE-2026-107804 carries a CVSS v3.1 score of 5.3 (Medium) with vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L. The attack vector is Network, requiring no privileges or user interaction.
The primary severity stems from the Denial of Service vector. By forcing a temporary ban on 127.0.0.1, an attacker can repeatedly block all remote administrative access to the platform. Systems utilizing automated password or OTP authentication are particularly sensitive to this brute-force lockout cycle.
While the IP allowlist bypass permits unauthorized network paths to reach the login interface, direct privilege escalation or data leakage requires valid credentials. Consequently, Integrity and Confidentiality impacts are evaluated as None in the standard CVSS assessment.
System administrators running Nginx UI must update to version 2.6.0 or higher. For Docker installations, pull the updated container image using docker compose pull nginx-ui and restart the service via docker compose up -d --force-recreate nginx-ui.
If Nginx UI is hosted behind additional upstream proxy infrastructure (such as Cloudflare, AWS ALB, or an external Nginx load balancer), update app.ini to explicitly declare the trusted network boundaries under the [auth] section.
[auth]
TrustedProxies = 127.0.0.1
TrustedProxies = 10.0.0.0/8Alternatively, set the environment variable NGINX_UI_AUTH_TRUSTED_PROXIES="127.0.0.1,10.0.0.0/8". Administrators must never configure TrustedProxies to wildcards like 0.0.0.0/0 or ::/0, as this would allow untrusted external clients to spoof X-Forwarded-For headers.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Attribute | Detail |
|---|---|
| CWE ID | CWE-346 (Origin Validation Error) |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 | 5.3 (Medium) |
| EPSS Score | N/A |
| Impact | IP Allowlist Bypass, Denial of Service |
| Exploit Status | No public PoC available |
| CISA KEV Status | Not Listed |
Nginx UI versions 2.5.0 through 2.5.10 contain an uncontrolled resource consumption vulnerability in the node authentication handler. Unauthenticated remote attackers can exhaust host disk storage and I/O resources by submitting large HTTP request bodies to node-signature endpoints prior to cryptographic signature validation.
Vikunja versions 2.3.0 through 2.6.0 contain an insufficient session expiration vulnerability (CWE-613) within the WebSocket authentication handler. Although Vikunja enforces server-side session tracking and revocation for REST API routes, the WebSocket handshake handler validates cryptographic JWT signatures without querying the database session state. Consequently, revoked JWT tokens can establish new real-time WebSocket connections, and existing connections persist after session revocation.
A cross-tenant boundary breach vulnerability in Vikunja allows an authenticated user to trigger global task position recalculations across all tenant instances by creating a saved filter with an empty filter string payload.
An access revocation flaw in Vikunja allows removed collaborators to retain outbound webhooks and link shares created prior to revocation, enabling persistent exfiltration of sensitive task data.
Vikunja v2.6.0 contains a permission inheritance regression in pkg/models/project_access.go where explicit down-restrictions on sub-projects are overridden by higher parent project permissions due to MAX aggregation across project tree nodes.
An authorization bypass vulnerability in Vikunja's link share deletion handlers allows project members with Write privileges to delete Admin-tier link shares. The handler passes an unpopulated struct to the authorization check, causing the permission evaluation to fall back to default Write permissions instead of requiring Admin privileges.