github.com /0xJacky/nginx-ui/security/advisories/GHSA-p393-cf76-4jmr
An authenticated nginx-ui administrator with an active secure session can call POST /api/restore , upload a forged portable or encrypted backup, restore app.ini , overwrite protected 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 .
Difference from CVE-2026-42238
CVE-2026-42238 addressed unauthenticated access to backup restore during the installation window and was fixed in nginx-ui 2.3.8 by enforcing authentication on the restore route. This advisory covers a distinct post-authentication trust-boundary failure: after that fix, an authenticated administrator with an active secure session could still supply portable backup key material and a corresponding manifest, causing protected application settings to be accepted from an untrusted backup.
The post-authentication issue was reproduced on nginx-ui 2.3.11 and required an independent fix in commit a467ed652591fc0cd1b466a1ec751b493faef9f7 , released in 2.5.0. The 2.3.8 authentication fix does not prevent this attack. The distinct post-authentication variant is tracked for versions >= 2.3.8, < 2.5.0 .
An authenticated administrator with an active secure session 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:
/api/restore is reachable by an authenticated administrator after the secure-session check. The restore handler then 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.
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
nginx-ui is already running.
$TOKEN is a valid administrator JWT associated with an active secure session.
$CONTAINER is the local disposable Docker container name for cleanup and evidence checks.
Run only against a disposable local instance.
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.
Classify backups by trust level, authenticate current-server backups with a server-held secret, reject invalid signatures, and retain every protected setting during portable/AES restores. Parse app.ini through typed settings, validate the complete staged restore tree before touching live paths, and replace live files only after validation succeeds. This was implemented by commit a467ed652591fc0cd1b466a1ec751b493faef9f7 in 2.5.0.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
