TL;DR

On October 9, 2026, Nginx UI v2.5.0 shipped with fixes for six high-severity CVEs — all disclosed the same day, all affecting versions 2.0.0 through 2.4.x. One maintainer. One codebase. Six different ways to break authentication, authorization, or configuration integrity. The pattern is unmistakable: a single architectural gap — JWTs accepted without session proof — cascades into CSRF, passkey bypass, node impersonation, backup injection, and stale-role replay. Fix one, find five more hiding behind the same assumption.

The Six

All six CVEs hit the range 2.0.0–2.4.x and were fixed in v2.5.0 on October 9, 2026:

CVEFlawPrimitive
CVE-2026-107808Passkey-only accounts issued session after password aloneAuth bypass
CVE-2026-107809JWT cookie accepted by AuthRequired without CSRF tokenCSRF
CVE-2026-107810Backup restore extracts symlinks targeting live configConfig injection
CVE-2026-107811Node token from /api/nodes accepted by AuthRequiredCross-node auth bypass
CVE-2026-107813AuthRequired without RequireSecureSession on cluster endpointsStale JWT elevation
CVE-2026-107812Upgrade digest validated against same-origin mirror onlyCompromised mirror → RCE

That’s five authentication/authorization flaws and one supply-chain flaw. Five of six are different attack vectors on the same session management layer.

The Root Cause

Every auth-related CVE traces to the same assumption: if a user has a JWT, they’re authenticated enough.

AuthRequired checks the JWT. It checks OTP. But it does not call RequireSecureSession — which would verify that the session was established with a second factor. This means:

  • A stolen JWT from before a passkey was added works indefinitely (107813)
  • A password-only account with passkey enabled gets a session without the passkey (107808)
  • The JWT cookie works across origins without CSRF protection (107809)
  • A node token from /api/nodes maps to initUser via AuthRequired (107811)

The maintainer didn’t forget to secure each endpoint individually. They built a gate that only checks the token, not how it was earned. Every endpoint that sits behind that gate inherits the same weakness — just expressed differently.

The Backup Injections

CVE-2026-107810 (backup symlink injection) is the outlier — not auth-related, but still a product of the same design philosophy: trust the authenticated user’s choices. The restore logic extracts inner archives before applying flags and permits symlinks. Crafted backup → symlink staging tree → regular file write through the link → persistent config injection. Even when both restore_nginx and restore_nginx_ui flags are false.

CVE-2026-107812 (upgrade digest validation) is a sibling: trust the same-origin mirror, validate the digest, install. Compromised mirror or network attacker altering both the binary and digest → malicious executable running in the Nginx UI process context.

Both are “authentic user, crafted input, trust too much” — same pattern, different layer.

What This Means for Single-Developer Projects

Nginx UI is maintained by a single developer. The six CVEs aren’t a sign of incompetence — they’re a sign of the cost of context switching. The maintainer fixed the CSRF by adding RequireSecureSession. Then they looked at the backup logic and saw the symlink issue. Then the passkey bypass. Then the node token. Each fix reveals another angle on the same gap.

This is why single-maintainer projects often ship with “one fix” that turns out to be five:

  1. The maintainer spots the obvious attack vector and fixes it.
  2. They test — and the next vector appears.
  3. They fix that too — and realize the session layer is underspecified.
  4. They add RequireSecureSession — and the remaining CVEs resolve together.

The lesson isn’t “hire more maintainers.” It’s: when you find one auth flaw, audit the whole session layer. Don’t fix CVEs one at a time — fix the assumption they’re all built on.

The Fix in v2.5.0

The fix is architectural, not cosmetic:

  • AuthRequired now calls RequireSecureSession on management endpoints, which verifies a second-factor step-up for OTP-enabled accounts.
  • The backup restore logic validates symlink targets against the extraction directory.
  • Upgrade digest validation uses a signed manifest rather than same-origin only.
  • The node token is scoped to its origin node.

The cascade of six CVEs was really one cascade: one missing session proof, six expressions of it.

Actionable Takeaways

1. When you find one auth bypass, audit the session layer. Don’t fix the CVE and move on. Find every endpoint that trusts the JWT, check whether it verifies the session, and fix them together.

2. Map your authentication assumptions. Write down every point where your code accepts “the user is authenticated” — JWT check, cookie read, token validation. For each one, ask: “Does this verify how the user was authenticated, or just that they authenticated?”

3. Single-maintainer projects need auth audits. A second set of eyes on the session layer finds the vectors the maintainer’s context window misses. Two hours of auth review saves six CVEs.

4. Backup logic is an attack surface. Authenticated users can upload files. If those files get extracted, symlinks resolved, or flags applied, a crafted backup is a backdoor. Validate the entire restore chain — not just the file content, but the paths.

5. Supply-chain validation should survive a compromised mirror. Same-origin digest check is necessary but not sufficient. Signed manifest with key rotation is better. The mirror can lie — the key shouldn’t.

Further Reading