# Nginx-UI: Unauthenticated first-boot instance claim via POST /api/install allows remote bootstrap takeover

Unauthenticated POST /api/install on a fresh nginx-ui instance lets a remote attacker set admin credentials and JWT/node secrets, claiming the install.

- Payout: Research
- Severity: high
- Program: Nginx-UI
- Found by: Kakeru-Ishii
- Disclosed: 2026-05-06
- CVE: CVE-2026-42222
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-mxqh-q9h6-v8pq
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-mxqh-q9h6-v8pq
- Tags: area:web domain:web impact:ato impact:privesc kind:research platform:ghsa sev:high tech:go technique:default-creds vuln:access-control vuln:auth-bypass vuln:misconfiguration

**Target:** First-run setup endpoint POST /api/install of nginx-ui
**Root cause:** The install handler is reachable without authentication while the instance is uninitialized and accepts attacker-supplied bootstrap data (admin user/password, JWT secret, node secret, cert email), relying only on a 10-minute setup window as protection.
**Steps:**
1. Start fresh nginx-ui v2.3.5 container with empty /etc/nginx and /etc/nginx-ui.
2. `GET /api/install` returns `{"lock":false,"timeout":false}` confirming uninitialized state.
3. Fetch RSA public key: `POST /api/crypto/public_key` with `{"timestamp":...,"fingerprint":"install-takeover-poc"}`.
4. Encrypt `{"email":...,"username":...,"password":...}` with the public key (PKCS1) and base64 it.
5. `POST /api/install` with `{"encrypted_params":"<base64>"}` returns `{"message":"ok"}`.
6. `GET /api/install` now returns `{"lock":true,"timeout":false}`.
7. `POST /api/login` with the same encrypted credentials returns a valid token/short_token.
**How found:** Reporter examined the first-run install flow and noticed POST /api/install was exempt from authentication while uninitialized, with only a time-window gate; verified by driving the full bootstrap sequence against a live container.
**Exploitation:** Attacker with network reach to a fresh instance during the setup window fetches the install public key, encrypts chosen admin credentials, and posts them to /api/install, becoming the first administrator and defining JWT/node secrets; then logs in normally to obtain a session token.
**Escalation:** Full administrative control of the instance plus control over application trust material (JWT secret, node secret), enabling persistent authenticated access.
**Insight:** First-run/bootstrap endpoints that accept secrets (admin creds, JWT keys) are a takeover primitive: check whether the only gate is an uninitialized flag or timer, and whether the setup key endpoint is also unauthenticated so you can encrypt your own payload.

## Proof of concept (copied exactly from the original report)

**Docker command starting fresh vulnerable instance**

```
docker run -d --rm --name nginx-ui-poc \
  -v "$PWD/.tmp/poc-nginx:/etc/nginx" \
  -v "$PWD/.tmp/poc-nginx-ui:/etc/nginx-ui" \
  uozi/nginx-ui@sha256:d73343e3009c9b558129a2be0cacd6c2c57ed8006a5871873b874b812e612e5a
```

