CVE-2026-107810: Nginx UI Backup Restore Follows Crafted Symlinks Vulnerability

HIGH
Advisory Identifier: GHSA-p8v3-89rh-jxc7
CVSS 8.1
CWE-59 CWE-61
Published
Advisory Summary

CVE-2026-107810 is a HIGH (CVSS 8.1) backup restore follows crafted symlinks vulnerability (CWE-59: Improper Link Resolution Before File Access ('Link Following')) affecting Nginx UI libraries in the Go ecosystem. The issue involves backup restore follows crafted symlinks into the live nginx configuration path before restore flags are applied. Remediation is available by upgrading affected packages to version 1.9.10-0.20260728074146-a467ed652591.

CVE-2026-107810 at a Glance

CVE Identifier CVE-2026-107810
GHSA Identifier GHSA-p8v3-89rh-jxc7
Severity HIGH
CVSS v3.1 Base Score 8.1
CWE Classification CWE-59: Improper Link Resolution Before File Access ('Link Following')
Affected Product Nginx UI
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 8.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2026-107810

To remediate this vulnerability, upgrade all affected Nginx UI dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/0xJacky/Nginx-UI fixed: 1.9.10-0.20260728074146-a467ed652591
Upgrade github.com/0xJacky/Nginx-UI to 1.9.10-0.20260728074146-a467ed652591
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/0xJacky/Nginx-UI

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-107810, inspect your project dependencies for Nginx UI:

inspect dependencies for github.com/0xJacky/Nginx-UI

Analyze the terminal output to locate any version of Nginx UI in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.9.10-0.20260728074146-a467ed652591), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-59: Improper Link Resolution Before File Access ('Link Following'), where the product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource. In Nginx UI, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### 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](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:39) - [internal/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:79) - [internal/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:204) - [internal/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/internal/backup/restore.go:286) - [api/backup/restore.go](/home/kali/Desktop/bounty/nginx-ui/api/backup/restore.go:31) - [api/backup/backup.go](/home/kali/Desktop/bounty/nginx-ui/api/backup/backup.go:15) 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.

CVE-2026-107810 Affected Nginx UI Versions

1 component(s)
Fixed Versions:
1.9.10-0.20260728074146-a467ed652591
Product / Package Ecosystem Affected Versions Fixed Version
github.com/0xJacky/Nginx-UI
Go
≥ 1.9.10-0.20250517140552-daee3ac7ade1
< 1.9.10-0.20260728074146-a467ed652591
1.9.10-0.20260728074146-a467ed652591

References

Frequently Asked Questions

What is CVE-2026-107810?
CVE-2026-107810 is a security vulnerability in Nginx UI involving Backup restore follows crafted symlinks into the live Nginx configuration path before restore flags are applied under CWE-59: Improper Link Resolution Before File Access ('Link Following').
Which Nginx UI versions are affected?
Affected versions include releases prior to 1.9.10-0.20260728074146-a467ed652591 across affected packages: github.com/0xJacky/Nginx-UI.
What version fixes CVE-2026-107810?
Upgrading to 1.9.10-0.20260728074146-a467ed652591 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/0xJacky/Nginx-UI affected?
Yes, github.com/0xJacky/Nginx-UI is affected in releases prior to 1.9.10-0.20260728074146-a467ed652591. Upgrade your dependency to 1.9.10-0.20260728074146-a467ed652591 or later.
What is the CVSS score of CVE-2026-107810?
CVE-2026-107810 has a CVSS v3.1 base score of 8.1 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H.
What CWE is associated with CVE-2026-107810?
CVE-2026-107810 is classified under CWE-59: Improper Link Resolution Before File Access ('Link Following') (The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource.).
How can I check Go dependencies for CVE-2026-107810?
Run the dependency tree command: 'inspect dependencies for github.com/0xJacky/Nginx-UI'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-p8v3-89rh-jxc7",
  "modified" : "2026-10-09T17:07:05Z",
  "published" : "2026-10-09T17:07:05Z",
  "aliases" : [ "CVE-2026-107810" ],
  "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.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/0xJacky/Nginx-UI"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "1.9.10-0.20250517140552-daee3ac7ade1"
      }, {
        "fixed" : "1.9.10-0.20260728074146-a467ed652591"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-p8v3-89rh-jxc7"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/0xJacky/nginx-ui/commit/a467ed652591fc0cd1b466a1ec751b493faef9f7"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/0xJacky/nginx-ui"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/0xJacky/nginx-ui/releases/tag/v2.5.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-59", "CWE-61" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-09T17:07:05Z",
    "nvd_published_at" : null
  }
}