CVE-2026-107813
Nginx UI: Incomplete fix of CVE-2026-84315 - the api/cluster router was not - wrapped in RequireSecureSession, so those sensitive mutations run without OTP step-up
Nginx UI is a web user interface for the Nginx web server. From 2.0.0 until 2.5.0, the api/cluster router exposes node and namespace mutation operations and cluster-wide Nginx reload or restart operations with AuthRequired but without RequireSecureSession. An authenticated OTP-enabled user possessing a stolen or persisted JWT can therefore perform node CRUD, read or replace node credentials, change namespaces, and invoke nodes/reload_nginx or nodes/restart_nginx without a fresh second-factor step-up. This issue is an incomplete fix for CVE-2026-84315 and is fixed in version 2.5.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.8
Nginx UI: Incomplete fix of CVE-2026-84315 - the api/cluster router was not - wrapped in RequireSecureSession, so those sensitive mutations run without OTP step-up
Nginx UI is a web user interface for the Nginx web server. From 2.0.0 until 2.5.0, the api/cluster router exposes node and namespace mutation operations and cluster-wide Nginx reload or restart operations with AuthRequired but without RequireSecureSession. An authenticated OTP-enabled user possessing a stolen or persisted JWT can therefore perform node CRUD, read or replace node credentials, change namespaces, and invoke nodes/reload_nginx or nodes/restart_nginx without a fresh second-factor step-up. This issue is an incomplete fix for CVE-2026-84315 and is fixed in version 2.5.0.
- Record
CVE-2026-107813- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
EUVDEUVD-2026-95898
8.8
Nginx UI is a web user interface for the Nginx web server. From 2.0.0 until 2.5.0, the api/cluster router exposes node and namespace mutation operations and cluster-wide Nginx reload or restart operations with AuthRequired but without RequireSecureSession. An authenticated OTP-enabled user possessing a stolen or persisted JWT can therefore perform node CRUD, read or replace node credentials, change namespaces, and invoke nodes/reload_nginx or nodes/restart_nginx without a fresh second-factor step-up. This issue is an incomplete fix for CVE-2026-84315 and is fixed in version 2.5.0.
- Record
EUVD-2026-95898- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-h246-wpgf-vmq5
8.8
Nginx UI: Incomplete fix of CVE-2026-84315 - the api/cluster router was not - wrapped in RequireSecureSession, so those sensitive mutations run without OTP step-up
Summary
Incomplete fix of GHSA-5v7c-xpfp-p65m: the secure-session (OTP step-up) requirement added to the nginx, cert, dns, backup, site, and stream mutation routers was not applied to the parallel api/cluster router, so cluster node management and cluster-wide nginx reload/restart run with only a JWT and no step-up. An authenticated user whose JWT is stolen or persisted, but who does not hold a fresh secure-session, can perform cluster node CRUD (including reading and rewriting a node token secret) and trigger cluster-wide nginx reload/restart. Confirmed at HEAD 2cb7ee9102c9d87274de2fa104db804841d140a0.
The defect
GHSA-5v7c-xpfp-p65m required a fresh secure session (an OTP step-up beyond the JWT) for sensitive mutation routes. The fix wrapped the nginx, cert, dns, backup, site, and stream mutation handlers in middleware.RequireSecureSession() and added reload/restart to the MCP sensitive-tool list. It did not touch the physically separate api/cluster package, whose router registers the same class of sensitive operations on the bare authenticated group.
The fixed sibling, api/nginx/router.go:
o := r.Group("", middleware.RequireSecureSession()) // line 28
{
o.POST("nginx/reload", Reload) // line 30
o.POST("nginx/restart", Restart) // line 31
}
The missed router, api/cluster/router.go, registers every sensitive operation directly on r with no RequireSecureSession wrapper:
nodeGroup := r.Group("nodes") // line 9, no step-up
{
nodeGroup.POST("", AddNode) // line 12
nodeGroup.POST("/:id", EditNode) // line 13
nodeGroup.DELETE("/:id", DeleteNode) // line 14
}
r.POST("nodes/reload_nginx", ReloadNginx) // line 17
r.POST("nodes/restart_nginx", RestartNginx) // line 18
r.POST("namespaces", AddNamespace) // line 22
r.POST("namespaces/:id", ModifyNamespace) // line 23
r.DELETE("namespaces/:id", DeleteNamespace) // line 24
Both routers mount on the same group in router/routers.go: g := root.Group("/", middleware.AuthRequired(), middleware.Proxy()) (line 87); nginx.InitRouter(g) creates its own RequireSecureSession subgroup, cluster.InitRouter(g) does not. So the cluster routes inherit only AuthRequired and Proxy, exactly the pre-fix posture the advisory closed for the nginx routes. AuthRequired has no role gate, so any authenticated user reaches them.
Attacker model and impact
An authenticated, OTP-enabled user who does not present a fresh X-Secure-Session-ID (the parent advisory's model: a stolen or persisted JWT used without the step-up). Such a user can: add/edit/delete cluster nodes (AddNode/EditNode store an AES-serialized node token, the secret used to control a remote node, so this reads back and rewrites a cross-node credential); trigger nodes/reload_nginx and nodes/restart_nginx across the cluster (the exact reload/restart action class the fix protected on the single-node path); and add/modify/delete/reorder namespaces.
Proof of concept: with a valid JWT but no fresh secure session, call POST /api/nodes (AddNode) or POST /api/nodes/reload_nginx. The nginx equivalent POST /api/nginx/reload returns the secure-session challenge; the cluster route succeeds.
Verification
Source-verified at HEAD: the nginx router wraps reload/restart in RequireSecureSession, the cluster router registers node/namespace/reload/restart directly on the group with no such wrapper, and both mount on the AuthRequired+Proxy-only group. I did not stand up a live nginx-ui.
Suggested fix
Wrap the cluster router's mutation handlers (node CRUD, nodes/reload_nginx, nodes/restart_nginx, namespace CRUD) in middleware.RequireSecureSession(), mirroring api/nginx/router.go. Secondary lower-confidence items worth checking in the same pass: the system/restart handler, the core-upgrade websocket, and the upstream socket…
- Record
GHSA-h246-wpgf-vmq5- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
NVD
8.8
Nginx UI is a web user interface for the Nginx web server. From 2.0.0 until 2.5.0, the api/cluster router exposes node and namespace mutation operations and cluster-wide Nginx reload or restart operations with AuthRequired but without RequireSecureSession. An authenticated OTP-enabled user possessing a stolen or persisted JWT can therefore perform node CRUD, read or replace node credentials, change namespaces, and invoke nodes/reload_nginx or nodes/restart_nginx without a fresh second-factor step-up. This issue is an incomplete fix for CVE-2026-84315 and is fixed in version 2.5.0.
- Record
CVE-2026-107813- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSV
8.8
Nginx UI: Incomplete fix of CVE-2026-84315 - the api/cluster router was not - wrapped in RequireSecureSession, so those sensitive mutations run without OTP step-up
Nginx UI is a web user interface for the Nginx web server. From 2.0.0 until 2.5.0, the api/cluster router exposes node and namespace mutation operations and cluster-wide Nginx reload or restart operations with AuthRequired but without RequireSecureSession. An authenticated OTP-enabled user possessing a stolen or persisted JWT can therefore perform node CRUD, read or replace node credentials, change namespaces, and invoke nodes/reload_nginx or nodes/restart_nginx without a fresh second-factor step-up. This issue is an incomplete fix for CVE-2026-84315 and is fixed in version 2.5.0.
- Record
CVE-2026-107813- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSVGHSA-h246-wpgf-vmq5
8.8
Nginx UI: Incomplete fix of CVE-2026-84315 - the api/cluster router was not - wrapped in RequireSecureSession, so those sensitive mutations run without OTP step-up
Summary
Incomplete fix of GHSA-5v7c-xpfp-p65m: the secure-session (OTP step-up) requirement added to the nginx, cert, dns, backup, site, and stream mutation routers was not applied to the parallel api/cluster router, so cluster node management and cluster-wide nginx reload/restart run with only a JWT and no step-up. An authenticated user whose JWT is stolen or persisted, but who does not hold a fresh secure-session, can perform cluster node CRUD (including reading and rewriting a node token secret) and trigger cluster-wide nginx reload/restart. Confirmed at HEAD 2cb7ee9102c9d87274de2fa104db804841d140a0.
The defect
GHSA-5v7c-xpfp-p65m required a fresh secure session (an OTP step-up beyond the JWT) for sensitive mutation routes. The fix wrapped the nginx, cert, dns, backup, site, and stream mutation handlers in middleware.RequireSecureSession() and added reload/restart to the MCP sensitive-tool list. It did not touch the physically separate api/cluster package, whose router registers the same class of sensitive operations on the bare authenticated group.
The fixed sibling, api/nginx/router.go:
o := r.Group("", middleware.RequireSecureSession()) // line 28
{
o.POST("nginx/reload", Reload) // line 30
o.POST("nginx/restart", Restart) // line 31
}
The missed router, api/cluster/router.go, registers every sensitive operation directly on r with no RequireSecureSession wrapper:
nodeGroup := r.Group("nodes") // line 9, no step-up
{
nodeGroup.POST("", AddNode) // line 12
nodeGroup.POST("/:id", EditNode) // line 13
nodeGroup.DELETE("/:id", DeleteNode) // line 14
}
r.POST("nodes/reload_nginx", ReloadNginx) // line 17
r.POST("nodes/restart_nginx", RestartNginx) // line 18
r.POST("namespaces", AddNamespace) // line 22
r.POST("namespaces/:id", ModifyNamespace) // line 23
r.DELETE("namespaces/:id", DeleteNamespace) // line 24
Both routers mount on the same group in router/routers.go: g := root.Group("/", middleware.AuthRequired(), middleware.Proxy()) (line 87); nginx.InitRouter(g) creates its own RequireSecureSession subgroup, cluster.InitRouter(g) does not. So the cluster routes inherit only AuthRequired and Proxy, exactly the pre-fix posture the advisory closed for the nginx routes. AuthRequired has no role gate, so any authenticated user reaches them.
Attacker model and impact
An authenticated, OTP-enabled user who does not present a fresh X-Secure-Session-ID (the parent advisory's model: a stolen or persisted JWT used without the step-up). Such a user can: add/edit/delete cluster nodes (AddNode/EditNode store an AES-serialized node token, the secret used to control a remote node, so this reads back and rewrites a cross-node credential); trigger nodes/reload_nginx and nodes/restart_nginx across the cluster (the exact reload/restart action class the fix protected on the single-node path); and add/modify/delete/reorder namespaces.
Proof of concept: with a valid JWT but no fresh secure session, call POST /api/nodes (AddNode) or POST /api/nodes/reload_nginx. The nginx equivalent POST /api/nginx/reload returns the secure-session challenge; the cluster route succeeds.
Verification
Source-verified at HEAD: the nginx router wraps reload/restart in RequireSecureSession, the cluster router registers node/namespace/reload/restart directly on the group with no such wrapper, and both mount on the AuthRequired+Proxy-only group. I did not stand up a live nginx-ui.
Suggested fix
Wrap the cluster router's mutation handlers (node CRUD, nodes/reload_nginx, nodes/restart_nginx, namespace CRUD) in middleware.RequireSecureSession(), mirroring api/nginx/router.go. Secondary lower-confidence items worth checking in the same pass: the system/restart handler, the core-upgrade websocket, and the upstream socket…
- Record
GHSA-h246-wpgf-vmq5- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSVGO-2026-6706 No score
Nginx UI: Incomplete fix of CVE-2026-84315 - the api/cluster router was not - wrapped in RequireSecureSession, so those sensitive mutations run without OTP step-up in github.com/0xJacky/Nginx-UI
Nginx UI: Incomplete fix of CVE-2026-84315 - the api/cluster router was not - wrapped in RequireSecureSession, so those sensitive mutations run without OTP step-up in github.com/0xJacky/Nginx-UI
- Record
GO-2026-6706- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/0xJacky/Nginx-UIGo |
1.9.10-0.20250517140552-daee3ac7ade1 up to 1.9.10-0.20260728074433-a3999bd78a3b | 1.9.10-0.20260728074433-a3999bd78a3b |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-107813 is a high vulnerability (CVSS 8.8) in Nginxui Nginx Ui, published October 9, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.30%, the 23rd percentile. Fixed in github.com/0xJacky/Nginx-UI 1.9.10-0.20260728074433-a3999bd78a3b.
References
github.com/0xJacky/nginx-ui/security/advisories/GHSA-h246-wpgf-vmq5
github.com/0xJacky/nginx-ui/commit/a3999bd78a3b97ab22e6b5e9fd478ac57598a954
github.com/0xJacky/nginx-ui/releases/tag/v2.5.0
github.com/advisories/GHSA-h246-wpgf-vmq5
github.com/CVEProject/cvelistV5/tree/main/cves/2026/107xxx/CVE-2026-107813.json
nvd.nist.gov/vuln/detail/CVE-2026-107813
github.com/0xJacky/nginx-ui
Left out here: the rest of 2 source descriptions. The JSON record has them.