Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-42238 — nginx-ui

🔴 CVSS 9.8 — Critical ✅ No Known Exploit CWE-94 NVD
9.8
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Nginx-UI is Vulnerable to Unauthenticated Remote Code Execution via Backup Restore

Product: nginx-ui

Repository: 0xJacky/nginx-ui (branch: dev)

Vulnerability Class: Authentication Bypass → Arbitrary File Write → OS Command Injection

Affected Component: POST /api/restore

1. Vulnerability Summary

nginx-ui exposes a backup restore endpoint (POST /api/restore) that is completely unauthenticated during the first 10 minutes after process startup on any fresh installation. An unauthenticated remote attacker can upload a crafted backup archive that overwrites the application's configuration file (app.ini) and SQLite database. Because the attacker controls the restored app.ini, they can inject an arbitrary OS command into the TestConfigCmd setting. After the application automatically restarts to apply the restored config, a single follow-up request triggers that command as the user running nginx-ui — typically root in Docker deployments.

The 10-minute unauthenticated window resets on every process restart, making this exploitable not only on initial deployments but on any restart event (container restart, upgrade, health-check-triggered restart).

2. Root Cause Analysis

2.1 The Restore Route Is Registered Without Authentication

backup.InitRouter is called on the root group, which carries only IPWhiteList() middleware — no AuthRequired(): [1](#2-0)

The route definition: [2](#2-1)

2.2 The authIfInstalled Guard Has a Time-Bounded Bypass

The only authentication guard on the restore route is authIfInstalled: [3](#2-2)

It calls AuthRequired() only when InstallLockStatus() || IsInstallTimeoutExceeded() is true. Both conditions are false on a fresh install within the first 10 minutes: [4](#2-3)

  • InstallLockStatus() returns false because JwtSecret is "" on a fresh install and SkipInstallation defaults to false.
  • IsInstallTimeoutExceeded() returns false for the first 10 minutes after startupTime is set in init().

When both are false, authIfInstalled calls ctx.Next() with zero authentication.

2.3 The EncryptedForm Middleware Is Not a Security Barrier

The EncryptedForm() middleware between authIfInstalled and RestoreBackup is optional — it only activates if the request includes an encrypted_params field. If that field is absent, it calls c.Next() immediately: [5](#2-4)

An attacker sends a plain multipart/form-data request without encrypted_params and the middleware is a no-op.

2.4 The Attacker Controls the AES Key Used to Verify the Backup

The restore handler accepts the AES key and IV directly from the attacker via the security_token form field: [6](#2-5)

The manifest integrity check derives its HMAC signing key from the attacker-supplied AES key: [7](#2-6)

Since the attacker crafts the backup and supplies the key, they can produce a valid HMAC signature for any manifest content they choose. The integrity check is self-referential and provides no security against a crafted backup.

2.5 Restore Overwrites app.ini and the SQLite Database Unconditionally

When restore_nginx_ui=true, restoreNginxUIConfig directly copies files from the backup onto disk with no content validation: [8](#2-7)

2.6 Restored TestConfigCmd Is Executed as a Shell Command

After restore, risefront.Restart() is called, reloading app.ini: [9](#2-8)

On the next call to TestConfig(), the value of TestConfigCmd from the restored app.ini is passed verbatim to /bin/sh -c: [10](#2-9) [11](#2-10)

3. Attack Prerequisites

| Requirement | Notes |

|---|---|

| Network access to nginx-ui port | Default: 9000/tcp |

| Target is a fresh install | JwtSecret is empty in app.ini |

| Within 10 minutes of last process start | Window resets on every restart |

| IP not blocked by IPWhiteList | Default config has no IP whitelist |

The 10-minute window is not a meaningful mitigation in practice. Docker containers restart frequently due to health checks, upgrades, and orchestrator rescheduling. Any restart resets startupTime via init(), reopening the window.

4. Step-by-Step Proof of Concept

Step 1 — Confirm the installation window is open

```http

GET /api/install HTTP/1.1

Host: target:9000

```

Expected response confirming vulnerability:

```json

{"lock": false, "timeout": false}

```

Step 2 — Craft the malicious backup

The backup format (derived from internal/backup/backup.go) is:

```

backup-TIMESTAMP.zip ← outer ZIP (unencrypted)

├── manifest.json ← JSON manifest

├── manifest.sig ← HMAC-SHA256 of manifest.json

├── nginx-ui.zip ← AES-CBC encrypted inner ZIP

└── nginx.zip ← AES-CBC encrypted inner ZIP

```

2a. Generate a random 32-byte AES key and 16-byte IV.

2b. Create the malicious app.ini to place inside nginx-ui.zip:

```ini

[app]

JwtSecret = attacker_chosen_jwt_secret_32chars

[node]

S

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality high, integrity high, availability high.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Privileges required: None — an unauthenticated stranger can try it.
  • User interaction: None — nobody has to be tricked into anything.
  • Scope: Unchanged — the damage stays inside the vulnerable component.
  • Confidentiality impact: High — total loss, or loss the attacker controls.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: High — total loss, or loss the attacker controls.

Weakness class

CVE-2026-42238 is classified as CWE-94: Code Injection. Input is incorporated into code that the runtime evaluates, so an attacker can have their own code executed.

Affected software

CVE-2026-42238 is recorded against 2 packages.

  • github.com/0xjacky/nginx-ui
  • nginx-ui (fixed in 2.3.8)

Timeline and source

Published on 25 June 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

github.com (Advisory)
nvd.nist.gov (Advisory)
github.com (Web)

Other advisories for this package

github.com/0xjacky/nginx-ui has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-94: Code Injection) in other software:

Details

Severity CRITICAL
CVSS Score 9.8
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE CWE-94
Public Exploit ✅ No
Source NVD
Published 2026-06-25
Updated 2026-08-20
Modified 2026-06-25
Fix URL N/A

Affected Packages

Software From version Fixed in
github.com/0xjacky/nginx-ui
nginx-ui 2.3.8

Similar Threats

Exploit Protection

Are you running nginx-ui?

CVE-2026-42238 carries CVSS 9.8 Critical rating. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.

Check My Site For CVE-2026-42238 →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026