GHSA-h246-wpgf-vmq5: High severity go/github.com/0xJacky/Nginx-UI vulnerability

Published Oct 9, 2026
·
Updated

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:

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:

go 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/reloadnginx", ReloadNginx) // line 17 r.POST("nodes/restartnginx", 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/reloadnginx and nodes/restartnginx 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/reloadnginx. 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/reloadnginx, nodes/restartnginx, 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 PUT also appear to run without the step-up (I did not fully trace these).

Affected Software

1 affected componentFixes available
go/github.com/0xJacky/Nginx-UI>=1.9.10-0.20250517140552-daee3ac7ade1<1.9.10-0.20260728074433-a3999bd78a3b
1.9.10-0.20260728074433-a3999bd78a3b

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade go/github.com/0xJacky/Nginx-UI to a version that resolves this vulnerability.

    Fixed in 1.9.10-0.20260728074433-a3999bd78a3b
  2. Configuration

    Wrap cluster mutation handlers in middleware.RequireSecureSession(), including node CRUD (POST /api/nodes, POST /api/nodes/:id, DELETE /api/nodes/:id), nodes/reload_nginx, nodes/restart_nginx, and namespace CRUD routes.

    api/cluster router middleware.RequireSecureSession() = enabled

Event History

Oct 9, 2026
Advisory Published
via GitHub·05:08 PM
Data Sourced
via GitHub·05:08 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Does exploitation require a fresh OTP-backed secure session?

No. An attacker needs an authenticated JWT but does not need a fresh secure session or OTP step-up. The advisory specifically describes risk from a stolen or persisted JWT.

2

What actions can an attacker take with only a JWT?

They can perform cluster node CRUD operations, including reading and rewriting a node token secret. They can also trigger cluster-wide nginx reload and restart operations.

3

Which code path was confirmed vulnerable?

The issue was confirmed at HEAD commit 2cb7ee9102c9d87274de2fa104db804841d140a0. The separate api/cluster router registered these sensitive operations on the authenticated group without the secure-session middleware used by sibling mutation routers.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203