Vulnerability GHSA-pvgv-gcp7-v38g

High Risk
HIGH RISK
CVSS Score: 8.8
Score Range: 7.0–8.9
High severity vulnerabilities (CVSS 7.0–8.9). Serious vulnerabilities that should be prioritized soon after critical fixes.
3 hours ago
October 09, 2026 at 05:07 PM UTC
Nginx UI: Node Secret Credential Exposure via URL Query Parameter
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074433-a3999bd78a3b
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074433-a3999bd78a3b

Summary

Nginx UI: Node Secret Credential Exposure via URL Query Parameter

Details

1. Vulnerability Summary

nginx-ui's Node.Secret is a master credential that bypasses all JWT/password authentication for the entire API. The application accepts this credential via a URL query parameter (?node_secret=), causing it to be recorded in plaintext in HTTP access logs, reverse proxy logs, browser history, and HTTP Referer headers. Additionally, the official cluster configuration format embeds node secrets directly into URL query strings stored in app.ini and environment variables, creating a systemic credential exposure pattern across the entire cluster deployment model.

An attacker who gains read access to any log aggregation system, proxy log, or configuration file can extract the node secret and obtain full, persistent, unauthenticated administrative access to the nginx-ui API — including reading TLS private keys, modifying nginx configurations, and (when chained with Bug #1) achieving OS-level code execution.

3. Exposure Surface

The following table maps each exposure vector to its source in the codebase:

Vector How It Happens Who Can See It
HTTP access logs GET /api/settings?node_secret=xxx logged by nginx/caddy/apache Log readers, SIEM operators
Application logs Gin debug mode logs full request URLs Server operators, log aggregators
Browser history Admin uses ?node_secret= URL directly Anyone with browser access
HTTP Referer header Page with ?node_secret= in URL links to external resource Third-party servers
WebSocket URL logs ws://host/api/ws?node_secret=xxx logged by proxies Proxy log readers
app.ini on disk Cluster node URLs contain node_secret= Filesystem readers
Environment variables NGINX_UI_CLUSTER_NODE=...&node_secret=... ps aux, Docker inspect, K8s pod specs
CI/CD pipeline logs Env vars printed during deployment CI/CD log viewers
Database nodes.token column stored in plaintext SQLite DB file readers

5. Impact

  • Confidentiality: Full read access to all nginx configurations, TLS private keys, ACME account credentials, database contents, and all settings stored in app.ini.
  • Integrity: Full write access to all nginx configurations across all cluster nodes. An attacker can deploy malicious nginx configs, disable TLS, or redirect traffic.
  • Availability: An attacker can reload or restart nginx with a broken configuration, causing a denial of service.
  • Persistence: The node secret does not expire and has no revocation mechanism. Once leaked, it provides permanent access until manually rotated.
  • Cluster-wide blast radius: A single leaked node secret from one cluster member's logs can be used to authenticate to any other node that shares the same secret.

7. Recommended Fixes

Fix 1 (Primary) — Remove query parameter support for node_secret:

// internal/middleware/middleware.go
func getNodeSecret(c *gin.Context) (secret string) {
    // Only accept via header, never via query parameter
    return c.GetHeader("X-Node-Secret")
}

Apply the same change to isTrustedNodeRequest in websocket_origin.go.

Fix 2 — Redesign cluster node configuration format:

The cluster node URL format must not embed secrets in query parameters. Use a separate configuration key:

[cluster]
Node     = http://10.0.0.1:9000?name=node1&enabled=true
NodeKey1 = <secret-for-node1>

Or store secrets in a separate secrets file with restricted permissions.

Fix 3 — Encrypt node tokens at rest:

The nodes.token column in the SQLite database stores secrets in plaintext. Encrypt using the CryptoSettings.Secret key before storage.

Fix 4 — Add secret rotation support:

Provide an API endpoint to rotate the Node.Secret and invalidate all existing sessions authenticated via the old secret.

Related Vulnerabilities

Other vulnerabilities affecting the same packages

High Risk
3 hours ago
Nginx UI: Self-upgrade runs an unsigned binary verified only by a same-origin digest → RCE via a compromised mirror or MITM
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728114330-580585516dd8 GHSA-662p-52hx-cmh2
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728114330-580585516dd8 GHSA-662p-52hx-cmh2
High Risk
3 hours ago
Nginx UI: Authentication bypass: password login does not enforce a passkey-only second factor (2FA bypass)
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074558-95cd21b70814 GHSA-45gv-9wjv-xh7p
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074558-95cd21b70814 GHSA-45gv-9wjv-xh7p
High Risk
3 hours ago
Nginx-UI AuthRequired token cookie fallback enables CSRF against management APIs
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074433-a3999bd78a3b GHSA-33rr-wq23-g6gg
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074433-a3999bd78a3b GHSA-33rr-wq23-g6gg
High Risk
3 hours ago
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
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074433-a3999bd78a3b GHSA-h246-wpgf-vmq5
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728074433-a3999bd78a3b GHSA-h246-wpgf-vmq5
High Risk
3 hours ago
0xJacky/nginx-ui /api/nodes Leaks Cluster Node Tokens and Allows Cross-Node Impersonation as initUser
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728091109-0ecbd106c37b GHSA-32gc-wf3m-78w9
>=1.9.10-0.20250517140552-daee3ac7ade1 <1.9.10-0.20260728091109-0ecbd106c37b GHSA-32gc-wf3m-78w9
View all vulnerabilities for these packages

Timeline

Published
3 hours ago
October 09, 2026 at 05:07 PM UTC
Last Modified
3 hours ago
October 09, 2026 at 05:15 PM UTC