Know every vulnerabilitybefore it knows you.
DevGuard continuously monitors your dependencies and alerts you when CVEs like this one affect your stack — with real-time threat intelligence built for developers.
GHSA-p8v3-89rh-jxc7
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 restore_nginx and restore_nginx_ui 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:
- Created a temporary
app.ini, database file, and a temporary live Nginx config directory. - Called the real
Backup()implementation to obtain a valid backup archive plus AES key/IV. - 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
- a symlink entry
- Recomputed
manifest.jsonsize/hash values for the modified encryptednginx.zipand re-signedmanifest.sigwith the expected signing key derived from the AES key. - Repacked the outer archive and called the real
Restore()implementation with:RestoreNginx: falseRestoreNginxUI: false
- Verified that
<live nginx conf dir>/poc.confwas 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.
Upload your own SBOM in CycloneDX 1.6 or higher (JSON) directly here to check your vulnerabilities.
Drag and drop some file here, or click to select
The vulnerability can be exploited over the network without needing physical access. It is easy for an attacker to exploit this vulnerability. An attacker needs basic access or low-level privileges. No user interaction is needed for the attacker to exploit this vulnerability. The impact is confined to the system where the vulnerability exists. There is a high impact on the integrity of the data. There is a high impact on the availability of the system.
Exploitation activity has been observed. Apply available patches or mitigations urgently.
The exploit probability is very low. The vulnerability is unlikely to be exploited in the next 30 days.
We did not find any exploit available. Neither in GitHub repositories nor in the Exploit-Database.
Browse More
Continuously monitor your dependencies and get alerted when vulnerabilities like this one affect your stack.
Checkout DevGuard