CVE-2026-84315
Nginx UI OTP secure-session step-up is missing on sensitive mutation routes
Nginx UI is a web user interface for the Nginx web server. Prior to 2.4.1, Nginx UI does not apply RequireSecureSession to multiple authenticated mutation routes even though OTP-enabled users are expected to present a fresh X-Secure-Session-ID for sensitive actions. A stolen authenticated session can therefore create or alter automatic backups, DNS credentials and records, certificates and ACME users, Nginx control settings, and site or stream automation without completing the OTP or passkey step-up. This issue is fixed in version 2.4.1.
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
- Low
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.3
Nginx UI OTP secure-session step-up is missing on sensitive mutation routes
Nginx UI is a web user interface for the Nginx web server. Prior to 2.4.1, Nginx UI does not apply RequireSecureSession to multiple authenticated mutation routes even though OTP-enabled users are expected to present a fresh X-Secure-Session-ID for sensitive actions. A stolen authenticated session can therefore create or alter automatic backups, DNS credentials and records, certificates and ACME users, Nginx control settings, and site or stream automation without completing the OTP or passkey step-up. This issue is fixed in version 2.4.1.
- Record
CVE-2026-84315- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
EUVDEUVD-2026-97830
8.3
Nginx UI is a web user interface for the Nginx web server. Prior to 2.4.1, Nginx UI does not apply RequireSecureSession to multiple authenticated mutation routes even though OTP-enabled users are expected to present a fresh X-Secure-Session-ID for sensitive actions. A stolen authenticated session can therefore create or alter automatic backups, DNS credentials and records, certificates and ACME users, Nginx control settings, and site or stream automation without completing the OTP or passkey step-up. This issue is fixed in version 2.4.1.
- Record
EUVD-2026-97830- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-5v7c-xpfp-p65m
8.3
Nginx UI OTP secure-session step-up is missing on sensitive mutation routes
Reporter: Jagadesh Achanta
Target: 0xJacky/nginx-ui
Affected version / commit tested:
- App version:
2.3.10 - Commit:
4948fba8744e82c3d7003f68ee164e9f49421066 - Disclosure channel: GitHub Private Vulnerability Reporting
- Credential reference:
cred:github-jagstack-gh-cli
AI assistance disclosure
This report was prepared by Jagadesh Achanta with assistance from OpenAI/Codex for public source review, local evidence collection, and report drafting.
Summary
Nginx UI has a short-lived OTP/passkey "secure session" step-up boundary for users with 2FA enabled. RequireSecureSession() rejects an OTP-enabled user's request unless the request includes a valid X-Secure-Session-ID issued after a fresh OTP/passkey verification.
The project already applies this step-up middleware to sensitive operations such as:
- Nginx config create/edit/rename/delete;
- site save/delete/enable/disable/rename/duplicate;
- stream save/delete/enable/disable/rename/duplicate;
- settings save and protected secret reads;
- backup restore.
However, several similarly sensitive authenticated mutation routes remain outside RequireSecureSession(). An attacker who obtains an authenticated JWT/session for a 2FA-enabled user, but does not have the victim's fresh OTP/passkey secure-session token, can still perform those operations.
The affected route groups include:
- automatic backup create/modify/delete/restore/test-S3 operations;
- DNS credential create/edit/delete operations;
- certificate and ACME user create/modify/delete/register operations;
- DNS domain, record, and DDNS create/update/delete operations;
- Nginx reload/restart, stub-status toggle, performance-setting update, and module-cache refresh operations;
- site/stream advanced-mode toggles and batch updates;
- auto-certificate binding/unbinding for sites;
- site navigation order and health-check updates.
This report is distinct from my earlier Nginx UI report about auto-backup path traversal. This report is about missing 2FA step-up authorization on sensitive authenticated mutation routes.
Why this is a security boundary
internal/middleware/secure_session.go only requires a secure-session token for users with OTP enabled. For OTP users, it reads X-Secure-Session-ID from the header or query string and aborts with 401 Unauthorized if the secure session is missing or invalid:
if !cUser.EnabledOTP() {
c.Next()
return
}
ssid := c.GetHeader("X-Secure-Session-ID")
if ssid == "" {
ssid = c.Query("X-Secure-Session-ID")
}
if ssid == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"message": "Secure Session ID is empty",
})
return
}
if user.VerifySecureSessionID(ssid, cUser.ID) {
c.Next()
return
}
internal/user/otp.go issues the secure-session ID for only 10 minutes:
func SetSecureSessionID(userId uint64) (sessionId string) {
sessionId = uuid.NewString()
cache.Set(secureSessionIDCacheKey(sessionId), userId, 10*time.Minute)
return
}
The UI/server already rely on this boundary for sensitive actions. For example, api/config/router.go wraps config mutations with RequireSecureSession():
o := r.Group("", middleware.RequireSecureSession())
{
o.POST("configs", AddConfig)
o.POST("config", EditConfig)
o.POST("config_mkdir", Mkdir)
o.POST("config_rename", Rename)
o.POST("config_delete", DeleteConfig)
}
api/sites/router.go protects normal site mutations:
o := r.Group("", middleware.RequireSecureSession())
{
o.POST("sites/:name/rename", RenameSite)
o.POST("sites/:name/enable", EnableSite)
o.POST("sites/:name/disable", DisableSite)
o.POST("sites/:name", SaveSite)
o.DELETE("sites/:name", DeleteSite)
o.POST("sites/:name/duplicate", DuplicateSite)
o.POST("sites/:name/maintenance", EnableMaintenanceSite)
}
api/streams/router.go protects normal stream mutations, and api/settings/router.go protects secret reads/settings saves:…
- Record
GHSA-5v7c-xpfp-p65m- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
NVD
8.3
Nginx UI is a web user interface for the Nginx web server. Prior to 2.4.1, Nginx UI does not apply RequireSecureSession to multiple authenticated mutation routes even though OTP-enabled users are expected to present a fresh X-Secure-Session-ID for sensitive actions. A stolen authenticated session can therefore create or alter automatic backups, DNS credentials and records, certificates and ACME users, Nginx control settings, and site or stream automation without completing the OTP or passkey step-up. This issue is fixed in version 2.4.1.
- Record
CVE-2026-84315- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSV
8.3
Nginx UI OTP secure-session step-up is missing on sensitive mutation routes
Nginx UI is a web user interface for the Nginx web server. Prior to 2.4.1, Nginx UI does not apply RequireSecureSession to multiple authenticated mutation routes even though OTP-enabled users are expected to present a fresh X-Secure-Session-ID for sensitive actions. A stolen authenticated session can therefore create or alter automatic backups, DNS credentials and records, certificates and ACME users, Nginx control settings, and site or stream automation without completing the OTP or passkey step-up. This issue is fixed in version 2.4.1.
- Record
CVE-2026-84315- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSVGHSA-5v7c-xpfp-p65m
8.3
Nginx UI OTP secure-session step-up is missing on sensitive mutation routes
Reporter: Jagadesh Achanta
Target: 0xJacky/nginx-ui
Affected version / commit tested:
- App version:
2.3.10 - Commit:
4948fba8744e82c3d7003f68ee164e9f49421066 - Disclosure channel: GitHub Private Vulnerability Reporting
- Credential reference:
cred:github-jagstack-gh-cli
AI assistance disclosure
This report was prepared by Jagadesh Achanta with assistance from OpenAI/Codex for public source review, local evidence collection, and report drafting.
Summary
Nginx UI has a short-lived OTP/passkey "secure session" step-up boundary for users with 2FA enabled. RequireSecureSession() rejects an OTP-enabled user's request unless the request includes a valid X-Secure-Session-ID issued after a fresh OTP/passkey verification.
The project already applies this step-up middleware to sensitive operations such as:
- Nginx config create/edit/rename/delete;
- site save/delete/enable/disable/rename/duplicate;
- stream save/delete/enable/disable/rename/duplicate;
- settings save and protected secret reads;
- backup restore.
However, several similarly sensitive authenticated mutation routes remain outside RequireSecureSession(). An attacker who obtains an authenticated JWT/session for a 2FA-enabled user, but does not have the victim's fresh OTP/passkey secure-session token, can still perform those operations.
The affected route groups include:
- automatic backup create/modify/delete/restore/test-S3 operations;
- DNS credential create/edit/delete operations;
- certificate and ACME user create/modify/delete/register operations;
- DNS domain, record, and DDNS create/update/delete operations;
- Nginx reload/restart, stub-status toggle, performance-setting update, and module-cache refresh operations;
- site/stream advanced-mode toggles and batch updates;
- auto-certificate binding/unbinding for sites;
- site navigation order and health-check updates.
This report is distinct from my earlier Nginx UI report about auto-backup path traversal. This report is about missing 2FA step-up authorization on sensitive authenticated mutation routes.
Why this is a security boundary
internal/middleware/secure_session.go only requires a secure-session token for users with OTP enabled. For OTP users, it reads X-Secure-Session-ID from the header or query string and aborts with 401 Unauthorized if the secure session is missing or invalid:
if !cUser.EnabledOTP() {
c.Next()
return
}
ssid := c.GetHeader("X-Secure-Session-ID")
if ssid == "" {
ssid = c.Query("X-Secure-Session-ID")
}
if ssid == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"message": "Secure Session ID is empty",
})
return
}
if user.VerifySecureSessionID(ssid, cUser.ID) {
c.Next()
return
}
internal/user/otp.go issues the secure-session ID for only 10 minutes:
func SetSecureSessionID(userId uint64) (sessionId string) {
sessionId = uuid.NewString()
cache.Set(secureSessionIDCacheKey(sessionId), userId, 10*time.Minute)
return
}
The UI/server already rely on this boundary for sensitive actions. For example, api/config/router.go wraps config mutations with RequireSecureSession():
o := r.Group("", middleware.RequireSecureSession())
{
o.POST("configs", AddConfig)
o.POST("config", EditConfig)
o.POST("config_mkdir", Mkdir)
o.POST("config_rename", Rename)
o.POST("config_delete", DeleteConfig)
}
api/sites/router.go protects normal site mutations:
o := r.Group("", middleware.RequireSecureSession())
{
o.POST("sites/:name/rename", RenameSite)
o.POST("sites/:name/enable", EnableSite)
o.POST("sites/:name/disable", DisableSite)
o.POST("sites/:name", SaveSite)
o.DELETE("sites/:name", DeleteSite)
o.POST("sites/:name/duplicate", DuplicateSite)
o.POST("sites/:name/maintenance", EnableMaintenanceSite)
}
api/streams/router.go protects normal stream mutations, and api/settings/router.go protects secret reads/settings saves:…
- Record
GHSA-5v7c-xpfp-p65m- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSVGO-2026-6775 No score
Nginx UI OTP secure-session step-up is missing on sensitive mutation routes in github.com/0xJacky/Nginx-UI
Nginx UI OTP secure-session step-up is missing on sensitive mutation routes in github.com/0xJacky/Nginx-UI
- Record
GO-2026-6775- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/0xJacky/Nginx-UIGo |
before 1.9.10-0.20260703131214-23d1934099b0 | 1.9.10-0.20260703131214-23d1934099b0 |
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-84315 is a high vulnerability (CVSS 8.3) in 0xjacky Nginx-ui, published October 12, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 27th percentile. Fixed in github.com/0xJacky/Nginx-UI 1.9.10-0.20260703131214-23d1934099b0.
References
github.com/0xJacky/nginx-ui/security/advisories/GHSA-5v7c-xpfp-p65m
github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2
github.com/0xJacky/nginx-ui/releases/tag/v2.4.1
nvd.nist.gov/vuln/detail/CVE-2026-84315
github.com/advisories/GHSA-5v7c-xpfp-p65m
github.com/CVEProject/cvelistV5/tree/main/cves/2026/84xxx/CVE-2026-84315.json
github.com/0xJacky/nginx-ui
Left out here: the rest of 2 source descriptions. The JSON record has them.