highCVSS 8.8Vulnerability

CVE-2026-84313

## Summary Endpoints that bind a TOTP secret (`POST /api/otp_enroll`) or register a WebAuthn passkey (`POST /api/finish_passkey_register`) for the *current* user require only a valid JWT. There is no current-password re-prompt and the routes are explicitly registered **outside** the `RequireSecureSession()` group. With only a stolen JWT, an attacker can attach their own second factor to the victim's account, surviving any subsequent password rotation and locking the legitimate user out. ## Details `api/user/router.go:34-39` — note the routes registered *before* the secure-session group: ```go r.GET("/otp_secret", GenerateTOTP) r.POST("/otp_enroll", EnrollTOTP) // ← outside RequireSecureSession r.GET("/begin_passkey_register", BeginPasskeyRegistration) r.POST("/finish_passkey_register", FinishPasskeyRegistration) // ← outside RequireSecureSession o := r.Group("", middleware.RequireSecureSession()) { o.GET("/otp_reset", ResetOTP) // reset *is* protected — inconsistent ... } ``` `EnrollTOTP` (`api/user/otp.go:45-102`) only refuses if `cUser.EnabledOTP()` is already `true`; for any victim who has never enabled TOTP it accepts an attacker-supplied `Secret` and `Passcode` pair (the validator only checks that the passcode is a valid TOTP for the supplied secret — i.e., the attacker proves they know the secret they are submitting): ```go if cUser.EnabledOTP() { ... abort ... } var twoFA struct { Secret string `json:"secret" binding:"required"` Passcode string `json:"passcode" binding:"required"` } if !cosy.BindAndValid(c, &twoFA) { return } if ok := totp.Validate(twoFA.Passcode, twoFA.Secret); !ok { ... abort ... } ciphertext, _ := crypto.AesEncrypt([]byte(twoFA.Secret)) u.Where(u.ID.Eq(cUser.ID)).Update(u.OTPSecret, ciphertext) ``` `FinishPasskeyRegistration` (`api/user/passkey.go`) is structurally identical and additionally has *no* "already enrolled" guard — an attacker can register multiple passkeys to

Properties

severity
high
summary
Nginx UI: TOTP / passkey enrolment requires no re-authentication, enabling persistent account takeover
cvss_score
8.8
retrieved_at
2026-10-15T22:56:51+00:00
ghsa_published
2026-10-15T20:11:32Z
source_url
https://github.com/advisories/GHSA-gfrc-g87h-7h5w
ghsa_updated
2026-10-15T20:11:33Z
ghsa_id
GHSA-gfrc-g87h-7h5w
last_source
GitHub Advisory Database
cve_id
CVE-2026-84313
cvss_vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
signal_observed_at
2026-10-15T22:56:51+00:00
is_ghsa_only
false

Related Entities (5)

VULNERABLE_TO (1)

←[Software]go/Nginx-UI

AFFECTS (1)

→[Software]go/Nginx-UI

HAS_WEAKNESS (2)

→[Weakness]Missing Authentication for Critical Function
→[Weakness]Improper Authentication

REPORTED_BY (1)

→[Source]GitHub Advisory Database

Explore deeper with Ninja Signal's threat intelligence graph

CVE-2026-84313 (CVSS 8.8) — Ninja Signal Threat Intelligence | Ninja Signal