{"schema":"threatline.record/2","record":{"id":"CVE-2026-107810","aliases":["GHSA-p8v3-89rh-jxc7","GO-2026-6707"],"summary":"Nginx UI: Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied","details":"### Summary\nAn 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`.\n\n### Details\nThe 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.\n\nRelevant code paths:\n- [internal/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:39)\n- [internal/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:79)\n- [internal/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:204)\n- [internal/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:286)\n- [api/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/api/backup/restore.go:31)\n- [api/backup/backup.go](/home/kali/Desktop/bounty/nginx-ui/api/backup/backup.go:15)\n\nThis 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.\n\n### PoC\nI verified this locally in an isolated environment with a temporary package-level harness that exercised the real `Backup()` and `Restore()` implementations.\n\nWhat the executed test did:\n1. Created a temporary `app.ini`, database file, and a temporary live Nginx config directory.\n2. Called the real `Backup()` implementation to obtain a valid backup archive plus AES key/IV.\n3. Extracted the outer backup, decrypted `nginx.zip`, replaced it with a crafted zip containing:\n   - a symlink entry `link -> <live nginx conf dir>`\n   - a later regular file entry `link/poc.conf`\n4. 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.\n5. Repacked the outer archive and called the real `Restore()` implementation with:\n   - `RestoreNginx: false`\n   - `RestoreNginxUI: false`\n6. Verified that `<live nginx conf dir>/poc.conf` was created anyway.\n\nObserved result from the actual local verification:\n- The crafted restore completed successfully with both restore flags set to `false`.\n- The asserted sink was the existence and content of the live-path file written during restore staging.\n\n### Impact\nAny 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.","categories":["Web servers"],"product":"github.com/0xJacky/Nginx-UI","vendor":"0xJacky","ecosystem":"go","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-p8v3-89rh-jxc7","source_modified_at":"2026-10-09T17:07:06Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/0xJacky/Nginx-UI"},"range":">= 1.9.10-0.20250517140552-daee3ac7ade1, < 1.9.10-0.20260728074146-a467ed652591"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-107810","source_modified_at":"2026-10-13T16:56:38.228Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"nginx-ui","vendor":"0xJacky","versions":[{"version":">= 2.0.0, < 2.5.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-p8v3-89rh-jxc7","source_modified_at":"2026-10-19T21:40:47.010282307Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"github.com/0xJacky/Nginx-UI","ecosystem":"Go","purl":"pkg:golang/github.com/0xJacky/Nginx-UI"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.9.10-0.20250517140552-daee3ac7ade1"},{"fixed":"1.9.10-0.20260728074146-a467ed652591"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-p8v3-89rh-jxc7","source_modified_at":"2026-10-09T17:07:06Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/0xJacky/Nginx-UI"},"version":"1.9.10-0.20260728074146-a467ed652591"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-p8v3-89rh-jxc7","source_modified_at":"2026-10-19T21:40:47.010282307Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"github.com/0xJacky/Nginx-UI","ecosystem":"Go","purl":"pkg:golang/github.com/0xJacky/Nginx-UI"},"version":"1.9.10-0.20260728074146-a467ed652591"}],"cvss":8.1,"severity":"High","kev":{"listed":false},"epss":{"probability":0.00392,"percentile":0.32199,"score_date":"2026-10-23"},"published_at":"2026-10-09T15:25:26.604Z","modified_at":"2026-10-19T21:40:47.010282307Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-p8v3-89rh-jxc7","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-09T17:07:06Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-107810","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-13T16:56:38.228Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-p8v3-89rh-jxc7","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-19T21:40:47.010282307Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-107810","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-p8v3-89rh-jxc7","tags":["exploit"]},{"source":"CVE List","url":"https://github.com/0xJacky/nginx-ui/commit/a467ed652591fc0cd1b466a1ec751b493faef9f7","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/0xJacky/nginx-ui/releases/tag/v2.5.0","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-p8v3-89rh-jxc7","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"poc","automatable":"no","technical_impact":"partial","assessed_at":"2026-10-13T16:56:11.014444Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"product","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-19T21:40:47.010282307Z","content_hash":"90bdc4c50e1d798b9cc60562ab73eaf228e8757c36bf334a84b8783500fd42cc"}}
