CVE-2026-107810: Nginx UI: Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied
Summary An authenticated user who can create and restore a backup can craft a valid backup archive that causes the restore staging process to write attacker-controlled files into the live Nginx configuration path even when both restorenginx and restorenginxui are set to false.
Details The restore flow always extracts the outer archive, verifies the manifest, decrypts nginx-ui.zip and nginx.zip, and extracts both inner archives before it decides whether RestoreNginx or RestoreNginxUI should be applied. The zip extractor explicitly allows absolute symlinks when the link target is under nginx.GetConfPath() or nginx.GetModulesPath(). Later regular-file entries are then created with os.OpenFile() on the symlinked path, which follows the symlink and writes into the live path.
Relevant code paths: - internal/backup/restore.go - internal/backup/restore.go - internal/backup/restore.go - internal/backup/restore.go - api/backup/restore.go - api/backup/backup.go
This means the restore trust boundary is broken during extraction. A restore request that explicitly opted out of restoring either Nginx or Nginx UI can still modify the live Nginx configuration tree during staging.
PoC I verified this locally in an isolated environment with a temporary package-level harness that exercised the real Backup() and Restore() implementations.
What the executed test did: 1. Created a temporary app.ini, database file, and a temporary live Nginx config directory. 2. Called the real Backup() implementation to obtain a valid backup archive plus AES key/IV. 3. Extracted the outer backup, decrypted nginx.zip, replaced it with a crafted zip containing: - a symlink entry link -> <live nginx conf dir> - a later regular file entry link/poc.conf 4. Recomputed manifest.json size/hash values for the modified encrypted nginx.zip and re-signed manifest.sig with the expected signing key derived from the AES key. 5. Repacked the outer archive and called the real Restore() implementation with: - RestoreNginx: false - RestoreNginxUI: false 6. Verified that <live nginx conf dir>/poc.conf was created anyway.
Observed result from the actual local verification: - The crafted restore completed successfully with both restore flags set to false. - The asserted sink was the existence and content of the live-path file written during restore staging.
Impact Any deployment that allows an authenticated user to create and restore backups is affected. A crafted restore archive can modify the live Nginx configuration path before either restore toggle is honored. This can lead to persistent configuration injection, denial of service on a later reload, or other follow-on impact depending on what files the deployment later consumes from the modified path.
Other sources
Nginx UI is a web user interface for the Nginx web server. From 2.0.0 until 2.5.0, internal/backup/restore.go extracts inner archives before applying the restorenginx and restorenginxui flags and permits symlinks targeting the live Nginx configuration path. An authenticated user who can create and restore backups can craft a valid backup that places a symlink in the staging tree and then writes a regular file through that link, even when both restore flags are false. This can persistently inject configuration or cause denial of service when the modified files are later consumed. This issue is fixed in version 2.5.0.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
go/github.com/0xJacky/Nginx-UIto a version that resolves this vulnerability.Fixed in 1.9.10-0.20260728074146-a467ed652591 - Upgrade
Upgrade
Nginx UIto a version that resolves this vulnerability.Fixed in 2.5.0
Event History
Frequently Asked Questions
Who can exploit this issue?
An authenticated user must be able to create and restore backups in Nginx UI. Exploitation does not require user interaction and can be performed over the network.
Are installations affected when Nginx restore options are disabled?
Yes. A crafted backup can write through a symlink into the live Nginx configuration path before the restore_nginx and restore_nginx_ui flags are applied, including when both flags are false.
What could an attacker accomplish?
An attacker can persistently inject Nginx configuration content or cause denial of service when the modified configuration files are later consumed.
What is the remediation?
Upgrade Nginx UI to version 2.5.0, which fixes the issue.