# Nginx UI: Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied

Nginx UI restore extracts crafted symlink plus file entry into live Nginx config path even with both restore flags false, enabling config injection.

- Payout: Research
- Severity: high
- Program: Nginx UI
- Found by: Vincent550102
- Disclosed: 2026-10-09
- CVE: CVE-2026-107810
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-p8v3-89rh-jxc7
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-p8v3-89rh-jxc7
- Tags: area:web domain:web impact:dos impact:integrity kind:research platform:ghsa sev:high tech:go technique:source-review vuln:file-upload vuln:misconfiguration vuln:path-traversal

**Target:** Backup restore archive extraction (zip) in Nginx UI
**Root cause:** Restore extracts and decrypts inner nginx.zip/nginx-ui.zip archives before checking RestoreNginx/RestoreNginxUI flags, and the zip extractor permits absolute symlinks whose targets fall under nginx.GetConfPath()/GetModulesPath(); subsequent regular-file entries are opened with os.OpenFile() on the symlinked path, following it into the live tree.
**Steps:**
1. Create temp app.ini, DB, and live Nginx config dir; call real `Backup()` to get valid archive plus AES key/IV.
2. Extract outer backup, decrypt `nginx.zip`, replace with crafted zip containing symlink entry `link -> <live nginx conf dir>` and later regular file entry `link/poc.conf`.
3. Recompute `manifest.json` size/hash for modified encrypted `nginx.zip` and re-sign `manifest.sig` with signing key derived from AES key.
4. Repack outer archive and call real `Restore()` with `RestoreNginx: false`, `RestoreNginxUI: false`.
5. Observe `<live nginx conf dir>/poc.conf` created despite both flags false.
**How found:** Code review of restore flow ordering: extraction/decryption of inner archives happens before RestoreNginx/RestoreNginxUI checks, and the extractor's symlink allowance for targets under GetConfPath()/GetModulesPath() combined with os.OpenFile() following links suggested a write into the live path.
**Exploitation:** Authenticated user with backup create/restore rights builds a valid signed backup, swaps the encrypted nginx.zip for one containing a symlink to the live conf dir plus a file entry under that symlink, re-signs the manifest, and submits restore; extraction writes attacker files into the live Nginx config path before restore toggles are honored.
**Escalation:** Persistent configuration injection into live Nginx tree, potentially DoS on reload or follow-on impact from files later consumed from that path.
**Insight:** When auditing archive restore, check whether extraction/decryption precedes the feature toggles that gate applying data, and whether the extractor whitelists symlinks by target prefix — a symlink entry plus a later file entry under it turns a read-only staging dir into a write primitive on the live path.

