
Docker-based lab environment to verify and exploit two unauthenticated API vulnerabilities (CVE-2026-42221, CVE-2026-42238) in nginx-ui, with patched version comparison and educational write-up.
This repository is for actually verifying two CVEs reported for nginx-ui (Nginx's Web GUI management tool) in a Docker environment.
Disclaimer
The verification content of this repository is intended only for isolated local environments that I manage.
Using similar methods on third-party systems without permission violates the Unauthorized Computer Access Law.
The verification process, considerations, and lessons learned are summarized in a Qiita article.
Actually trying out the nginx-ui CVEs: "Vulnerability" turned out to be a design story
| CVE | Summary | Affected Versions | Fixed Versions |
|---|
| CVE-2026-42221 | /api/install before setup is accessible without authentication. An attacker can register an admin account first | v2.3.7 and earlier | v2.3.8 |
| CVE-2026-42238 | /api/restore before setup is accessible without authentication. Arbitrary commands can be executed as root by injecting a malicious app.ini | v2.3.7 and earlier | v2.3.8 |
The two CVEs share the same root cause (the API window before setup is unprotected). In v2.3.8, both were fixed by introducing an installation secret method and adding a single middleware.
.
├── nginx_lab/ # Vulnerable version (v2.3.7) verification environment → port 8080
│ ├── Dockerfile # Image definition with initial settings to avoid startup loop
│ ├── docker-compose.yml
│ ├── nginx.conf # Configuration with corrected sites-enabled / stream blocks
│ ├── init-app.ini # Initial template for app.ini
│ └── entrypoint.sh # Initialization script at container startup
├── nginx_lab_patched/ # Patched version (v2.3.8) verification environment → port 8081
│ ├── Dockerfile
│ ├── docker-compose.yml
│ ├── nginx.conf
│ ├── init-app.ini
│ └── entrypoint.sh
├── scripts/
│ ├── exploit_42221.py # Attack script for CVE-2026-42221
│ ├── encrypt_password.py # RSA encryption utility
│ └── test_patched.py # Script to verify patch application on v2.3.8 (port 8081)
├── Qiita.md # Qiita draft manuscript
└── LearningPlan.md
pycryptodome librarypip install pycryptodome
cd nginx_lab
docker compose build
docker compose up -d
Check startup:
curl http://localhost:8080/api/install
# → OK if {"lock":false,"timeout":false} is returned
Gotcha: The base
uozi/nginx-ui:v2.3.7image will enter a startup loop as-is because directories likesites-enableddo not exist. The Dockerfile in this repository prepares these in advance.
cd scripts
python exploit_42221.py
If successful, you can log in to http://localhost:8080 with the attacker account.
cd nginx_lab_patched
docker compose build
docker compose up -d
In v2.3.8, the first-time setup requires an installation secret. After starting the container, check the secret.
docker exec nginx-ui-patched cat /etc/nginx-ui/.install_secret
Use this value in the setup screen at http://localhost:8081 to register an administrator.
cd scripts
python test_patched.py
If [OK] Attack failed (patched) is output, the patch is working correctly.
# Vulnerable version
cd nginx_lab
docker compose down -v
# Patched version
cd nginx_lab_patched
docker compose down -v