{"id":"GHSA-p8v3-89rh-jxc7","revision":null,"records":[{"revision":"77ebbd4ced2e40c8948b0397a8c31bbd","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-107810","aliases":[],"title":"Nginx UI: Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied","description":"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 restore_nginx and restore_nginx_ui 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.","state":0,"publishedAt":"2026-10-09T15:25:26.604+00:00","modifiedAt":"2026-10-13T16:56:38.228+00:00","affected":[{"ecosystem":"Vendor product","name":"nginx-ui","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"0xJacky\",\n                    \"product\": \"nginx-ui\",\n                    \"versions\": [\n                        {\n                            \"version\": \">= 2.0.0, < 2.5.0\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H","score":8.1,"severity":"HIGH"}],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-p8v3-89rh-jxc7","https://github.com/0xJacky/nginx-ui/commit/a467ed652591fc0cd1b466a1ec751b493faef9f7","https://github.com/0xJacky/nginx-ui/releases/tag/v2.5.0"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-107810","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-107810","identifiers":["CVE-2026-107810"]},"retained":false,"historicalAffected":[]},{"revision":"52d632ac283e40fdb46ef98f408838c9","observedAt":"2026-11-07T04:31:38.394+00:00","statement":{"source":"euvd","id":"EUVD-2026-95894","aliases":["CVE-2026-107810","GHSA-p8v3-89rh-jxc7"],"title":"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 restore_nginx and restore_nginx_ui flags and permits symlinks targeting the live Nginx…","description":"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 restore_nginx and restore_nginx_ui 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.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H","score":8.1,"severity":null}],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-p8v3-89rh-jxc7","https://github.com/0xJacky/nginx-ui/commit/a467ed652591fc0cd1b466a1ec751b493faef9f7","https://github.com/0xJacky/nginx-ui/releases/tag/v2.5.0"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-95894","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Oct 9, 2026, 3:25:26 PM","dateUpdated":"Oct 13, 2026, 4:56:38 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-95894","identifiers":["EUVD-2026-95894","CVE-2026-107810","GHSA-p8v3-89rh-jxc7"]},"retained":false,"historicalAffected":[]},{"revision":"85512788da0046b3b84d7b45e6cc8f93","observedAt":"2026-10-25T05:17:13.11+00:00","statement":{"source":"nvd","id":"CVE-2026-107810","aliases":[],"title":"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 restore_nginx and restore_nginx_ui flags and permits symlinks targeting the live Nginx…","description":"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 restore_nginx and restore_nginx_ui 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.","state":0,"publishedAt":"2026-10-09T16:17:25.54+00:00","modifiedAt":"2026-10-20T15:08:56.99+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H","score":8.1,"severity":"HIGH"}],"references":["https://github.com/0xJacky/nginx-ui/commit/a467ed652591fc0cd1b466a1ec751b493faef9f7","https://github.com/0xJacky/nginx-ui/releases/tag/v2.5.0","https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-p8v3-89rh-jxc7"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-107810","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Analyzed","weaknesses":["CWE-59","CWE-61"],"productCriteria":["cpe:2.3:a:nginxui:nginx_ui:*:*:*:*:*:*:*:*"],"sourceDates":{"published":"2026-10-09T16:17:25.540","lastModified":"2026-10-20T15:08:56.990"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-107810","identifiers":["CVE-2026-107810"]},"retained":false,"historicalAffected":[]},{"revision":"8c712d2529d745dabb64d5891cbe9687","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-p8v3-89rh-jxc7","aliases":["CVE-2026-107810","GO-2026-6707"],"title":"Nginx UI: Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied","description":"### 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.","state":0,"publishedAt":"2026-10-09T17:07:05+00:00","modifiedAt":"2026-10-19T21:40:47.0102823+00:00","affected":[{"ecosystem":"Go","name":"github.com/0xJacky/Nginx-UI","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"1.9.10-0.20250517140552-daee3ac7ade1"},{"kind":"fixed","version":"1.9.10-0.20260728074146-a467ed652591"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-p8v3-89rh-jxc7","https://github.com/0xJacky/nginx-ui/commit/a467ed652591fc0cd1b466a1ec751b493faef9f7","https://github.com/0xJacky/nginx-ui","https://github.com/0xJacky/nginx-ui/releases/tag/v2.5.0"],"sourceUrl":"https://github.com/advisories/GHSA-p8v3-89rh-jxc7","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-p8v3-89rh-jxc7","identifiers":["GHSA-p8v3-89rh-jxc7","CVE-2026-107810","GO-2026-6707"]},"retained":false,"historicalAffected":[]},{"revision":"666740f799164174bd2986e79cd16cdc","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-6707","aliases":["CVE-2026-107810","GHSA-p8v3-89rh-jxc7"],"title":"Nginx UI: Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied in github.com/0xJacky/Nginx-UI","description":"Nginx UI: Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied in github.com/0xJacky/Nginx-UI","state":0,"publishedAt":"2026-10-19T21:08:26+00:00","modifiedAt":"2026-10-19T21:31:49.0204829+00:00","affected":[{"ecosystem":"Go","name":"github.com/0xJacky/Nginx-UI","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"1.9.10-0.20250517140552-daee3ac7ade1"},{"kind":"fixed","version":"1.9.10-0.20260728074146-a467ed652591"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-p8v3-89rh-jxc7","https://github.com/0xJacky/nginx-ui/commit/a467ed652591fc0cd1b466a1ec751b493faef9f7","https://github.com/0xJacky/nginx-ui/releases/tag/v2.5.0"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-6707","license":"OSV · upstream source license applies","key":"osv:GO-2026-6707","identifiers":["GO-2026-6707","CVE-2026-107810","GHSA-p8v3-89rh-jxc7"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-08T13:04:23.5160344+00:00","complete":true,"records":1769,"lastAttemptAt":"2026-11-08T13:04:23.5160344+00:00","lastSuccessAt":"2026-11-08T13:04:23.701507+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:23.7015079+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-eaa64dac63caa79c8d4905619258c41c51b39e461b996124e1a21b5e85e7e738-5e9a1b25b88c72db8d3c46be95e52009e07ae4af884484ac8e34e4d7f79f07eb","complete":true,"records":421098,"lastAttemptAt":"2026-11-08T13:04:23.0585244+00:00","lastSuccessAt":"2026-11-08T13:04:23.0353669+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:23.0585244+00:00","snapshotPublishedAt":"2026-11-08T12:20:14+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-383c643166b94ac4b6a615647191978e","complete":true,"records":13654,"lastAttemptAt":"2026-11-08T13:04:50.0771652+00:00","lastSuccessAt":"2026-11-08T13:04:50.073+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:50.073+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13706,"expectedIdentifiers":13706,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-08T13:04:23.5160344+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-08T13:04:23.5160344+00:00","lastSuccessAt":"2026-11-08T13:04:23.7022986+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:23.7022987+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-d0adb98f65b04a798dd6ab08fb972092","complete":false,"records":13666,"lastAttemptAt":"2026-11-08T13:04:49.0861553+00:00","lastSuccessAt":"2026-11-08T13:04:49.083+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:49.083+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13185,"expectedIdentifiers":13706,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-980593e6977a6d1b4fb1eed5a1ffe88a468736f89f0a06f710924ad59132c023","complete":true,"records":9914,"lastAttemptAt":"2026-11-08T13:04:23.3678903+00:00","lastSuccessAt":"2026-11-08T11:07:07.068788+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:23.3678903+00:00","snapshotPublishedAt":"2026-11-08T11:02:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-fde804134ecdda0ddd5ff5c26ee1fff5a6fa659311f7ef2e51c6ad54964db0e2","complete":true,"records":1971,"lastAttemptAt":"2026-11-08T13:04:23.1502223+00:00","lastSuccessAt":"2026-11-06T19:03:17.0399903+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:23.1502223+00:00","snapshotPublishedAt":"2026-11-06T18:17:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-964c14035e6f0f6478b2870fad6a7ef9f6045876d4a12af2c2e514521e54b6af","complete":true,"records":3055,"lastAttemptAt":"2026-11-08T13:04:23.4767311+00:00","lastSuccessAt":"2026-11-08T11:07:12.1927025+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:23.4767311+00:00","snapshotPublishedAt":"2026-11-08T11:02:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-f8647d7ba64b1ba0dfdc7130944766d5b36d5b77d18fff0c79e651a4cff3c2b9","complete":true,"records":231293,"lastAttemptAt":"2026-11-08T13:04:23.2659134+00:00","lastSuccessAt":"2026-11-08T11:06:56.2918717+00:00","error":null,"lastVerifiedAt":"2026-11-08T13:04:23.2659134+00:00","snapshotPublishedAt":"2026-11-08T11:02:50+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}