A safe detector for the unauthenticated remote code execution chain in UniFi OS Server ≤ 5.0.6, disclosed in Ubiquiti Security Advisory Bulletin 064:

CVE Class Role in the chain
CVE-2026-34908 / CVE-2026-34909 Improper access control / path traversal Auth-gateway bypass (the foothold)
CVE-2026-34910 Improper input validation → command injection Unauthenticated RCE reached via the bypass

Fixed in UniFi OS Server 5.0.8.

Is it Safe to Run?

Yes. The detector is designed for production and assessment use:

  • No command is executed. The probe reaches the vulnerable endpoint without a required parameter, so the handler rejects the missing input and we confirm the bug from that validation error.
  • No target state is changed. Every request is a plain GET.
  • False-positive guard. A VULNERABLE verdict requires both that the auth-bypass reached the vulnerable handler and that a baseline request (same endpoint, no bypass) was correctly rejected with 401.

How it Works

UniFi OS fronts its services with nginx, which enforces authentication via a subrequest. That auth check treats any request whose raw URI begins with /api/auth/validate-sso/ as public, but nginx routes to the backend using the normalized URI (it percent-decodes %2f/ and collapses ../). A request like:

GET /api/auth/validate-sso/..%2f..%2f..%2fproxy/users/api/v2/ucs/update/latest_package

is therefore treated as public (raw prefix) yet routed to the authenticated internal package-update endpoint (normalized path). With no pkg_name, that endpoint replies query param pkg_name required — proving the bypass works and the vulnerable handler is reachable.

Probe response Verdict
200 + handler error markers VULNERABLE
400 (nginx rejects the divergence) PATCHED (5.0.8+)
401, UniFi OS fingerprint present INCONCLUSIVE (auth enforced / bypass blocked)
401, no UniFi OS fingerprint UNAFFECTED (not a UniFi OS Server)
anything else, no UniFi OS fingerprint UNAFFECTED (not a UniFi OS Server)
anything else, UniFi OS fingerprint present INCONCLUSIVE (unexpected response)

The detector also sends a baseline request to the same endpoint without the bypass and requires it to return 401 before declaring a host vulnerable. The check tests the vulnerable behavior directly — a VULNERABLE verdict means the bypass actually reached the sink.

Confirming the target is UniFi OS before any not-vulnerable verdict

Whenever the probe does not positively confirm VULNERABLE or PATCHED, the detector fetches the root page and looks for the UniFi OS management-portal fingerprint ( <title>UniFi OS</title>, window.UNIFI_OS_MANIFEST,id="portal-root", id="site-manager_portal-container"). This applies to a 401 too: a UniFi OS host that enforces auth on the bypass is INCONCLUSIVE, but a non-UniFi proxy that simply 401s everything carries no fingerprint and is reported UNAFFECTED. So every "not vulnerable" outcome is grounded in the fingerprint: markers present → INCONCLUSIVE; markers absent → UNAFFECTED (the CVE does not apply).

Requirements

  • Python 3.7+, standard library only — no third-party packages.

Usage

# single host (default port 11443)
./cve_2026_34908_check.py 192.168.1.10

# explicit port / URL forms
./cve_2026_34908_check.py host-a:11443 https://host-b

# scan a list, one target per line ('#' comments allowed), compact output
./cve_2026_34908_check.py -f targets.txt --brief

# machine-readable output for pipelines
./cve_2026_34908_check.py -f targets.txt --json > results.json

Options

Flag Description
targets One or more host, host:port, or https://host:port
-f, --targets-file FILE Read targets from a file (one per line; # comments)
--brief Single aligned line per target — ideal for scanning many hosts
--json Emit structured JSON results
--timeout SECS Per-request timeout (default: 10)
--no-color Disable coloured output (also honours NO_COLOR and non-TTY)

Examples

A vulnerable console (verbose, the default). The second line is the verdict's detail; the [!] marker and VULNERABLE render red on a TTY:

$ ./cve_2026_34908_check.py 192.168.1.10
[!] 192.168.1.10:11443: VULNERABLE
      auth bypass reached the vulnerable handler (no command executed); baseline correctly 401

A patched console (5.0.8+):

$ ./cve_2026_34908_check.py 192.168.1.11
[+] 192.168.1.11:11443: PATCHED
      nginx rejected the normalized-path divergence (HTTP 400) — 5.0.8+ behavior

A confirmed UniFi OS host the probe couldn't classifyINCONCLUSIVE. The detail line distinguishes the two cases (auth enforced vs. unexpected response):

$ ./cve_2026_34908_check.py 192.168.1.12 192.168.1.13
[?] 192.168.1.12:11443: INCONCLUSIVE
      bypass blocked / auth enforced (HTTP 401) on a confirmed UniFi OS host — not confirmed vulnerable
[?] 192.168.1.13:11443: INCONCLUSIVE
      UniFi OS detected, but probe returned an unexpected response: HTTP 302 text/html

A host that isn't UniFi OS at allUNAFFECTED (the advisory does not apply):

$ ./cve_2026_34908_check.py 203.0.113.9:443
[-] 203.0.113.9:443: UNAFFECTED
      no UniFi OS web fingerprint on / (probe HTTP 404) — target is not a UniFi OS Server

Scan a list, one aligned line per host (--brief). Exit status is 1 if any host is VULNERABLE, else 0 — handy in scripts:

$ ./cve_2026_34908_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE    192.168.1.10:11443
PATCHED       192.168.1.11:11443
INCONCLUSIVE  192.168.1.12:11443
UNAFFECTED    203.0.113.9:443
ERROR         10.0.0.1:11443  timeout
exit: 1

Machine-readable output for pipelines (--json). Each result carries the verdict plus the bypass.state/bypass.detail behind it; ERROR results carry an error field instead of bypass:

$ ./cve_2026_34908_check.py 192.168.1.10 192.168.1.11 10.0.0.1 --json
[
  {
    "target": "192.168.1.10:11443",
    "bypass": {
      "state": "vulnerable",
      "detail": "auth bypass reached the vulnerable handler (no command executed); baseline correctly 401"
    },
    "verdict": "VULNERABLE"
  },
  {
    "target": "192.168.1.11:11443",
    "bypass": {
      "state": "patched",
      "detail": "nginx rejected the normalized-path divergence (HTTP 400) — 5.0.8+ behavior"
    },
    "verdict": "PATCHED"
  },
  {
    "target": "10.0.0.1:11443",
    "verdict": "ERROR",
    "error": "timeout"
  }
]

Verdicts

Verdict Meaning
VULNERABLE Auth bypass reached the vulnerable handler unauthenticated. Patch to 5.0.8+.
PATCHED nginx rejected the normalized-path divergence (5.0.8+ behavior).
UNAFFECTED No UniFi OS portal fingerprint on the root page — the target is not a UniFi OS Server, so the advisory does not apply. Includes hosts that return 401 without the fingerprint (e.g. an unrelated proxy that rejects everything).
INCONCLUSIVE Confirmed UniFi OS host that couldn't be classified — verify the version manually. The verdict's detail line says which case: (a) the bypass was blocked / auth enforced (401), or (b) the probe returned an unexpected response.
ERROR Connection/timeout/TLS failure.

Exit codes

Code Meaning
0 No target returned VULNERABLE
1 At least one target is VULNERABLE
2 Usage error (bad arguments / unreadable targets file)

Limitations

  • INCONCLUSIVE is not a guarantee of safety — it confirms a UniFi OS host but couldn't classify it (auth enforced on the bypass, or an unexpected response). A host that is heavily filtered or fronted by an unexpected proxy may not be classifiable from the network alone. Confirm the running version where possible.
  • UNAFFECTED means the root page carried no UniFi OS portal fingerprint (including hosts that 401 without it). A UniFi OS console hidden behind a reverse proxy that strips or rewrites the portal HTML could therefore be misreported; confirm directly if the target is expected to be UniFi OS.
  • The detector reports reachability of the vulnerable behavior.

Remediation

Update UniFi OS Server to version 5.0.8 or later. The fix adds an nginx raw-vs-normalized URI comparison (closing the auth bypass) and input validation in the package-update path (closing the command injection).

Usage of this tool for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state, and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program.

See Also