| Название | Unitree Robotics Unitree Go2 (voice assistant component `chat_go`) 1.1.4/1.1.7/1.1.7.2 Improper Certificate Validation |
|---|
| Описание | Unitree Go2 chat_go WSS client disables TLS server certificate validation for its cloud LLM upstream, allowing upstream impersonation (CWE-295)
[SUMMARY]
The chat_go voice-assistant service of the Unitree Go2 robot (running as root) connects, for every conversation turn, to the cloud LLM upstream wss://gpt-proxy.unitree.com:6080/ws/chat. Its WebSocket client constructs the TLS context with check_hostname = False and verify_mode = ssl.CERT_NONE, i.e., server certificate validation is fully disabled, and the upstream hostname is a hardcoded domain resolved via unprotected system DNS.
A network-adjacent attacker who controls resolution of that hostname (router takeover / ARP spoofing / rogue access point; realized equivalently via an /etc/hosts entry in the authorized lab test) can serve a self-signed certificate (issuer=subject, no CA) that the robot accepts, completing TLS and a full business session. The robot then transmits its device serial number (user_id), the real upstream model name (gpt-4.1), and full conversation content to the attacker - and thereafter consumes an entirely attacker-controlled model-response stream: arbitrary natural-language replies (which the robot speaks aloud / displays as the model's answer), arbitrary structured function_call frames (executed as robot functions), and arbitrary python-style code blocks inside finish frames (parsed and mapped to the robot's built-in action table - demonstrated with handshake and nod gestures). No device contact, no credentials, and no user interaction are required.
[VULNERABLE CODE]
websocket.py, WebSocketClient.connect() - source-level in both firmware packages; on the tested 1.1.7 device the module ships compiled-only (bytecode contains CERT_NONE):
ssl_context = ssl.SSLContext()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
self.websocket = await websockets.connect(self.uri, ssl = ssl_context)
Hardcoded upstream (const.py): GPT_SERVER = 'gpt-proxy.unitree.com', GPT_PORT = '6080'; first-frame timeout MSG_TIMEOUT = 3.
[AFFECTED VERSIONS]
- Firmware package 1.1.4 (chat_go x.x.x.x): vulnerable (source)
- Firmware 1.1.7 (on-device runtime test, Go2 EDU): demonstrated
- Firmware package x.x.x.x Max Pro (chat_go x.x.x.x): identical code, not fixed
- Fixed version: unknown. The vendor's ticket tracker shows both related reports (#474 and #616) have passed their internal "fix confirmation" workflow stage; however, no fixed version has been communicated to the researcher (the 2026-09-08 email follow-up remains unanswered).
[SUGGESTED CVSS 3.1 - researcher's, for reference]
Demonstrated chain basis: AV:A/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N = 7.4 High (AC:H reflects the DNS-control prerequisite). If DNS hijacking is assessed as low difficulty (AC:L): 8.6 High. Note: the vendor report of 2026-09-03 cited 7.7/8.9 for these vectors; recomputation under the CVSS 3.1 specification yields 7.4/8.6 - the corrected values are used here.
[REPRODUCTION]
About 5 minutes, benign payload only (a compliant set_volume=50 frame - deliberately avoids the separately-reported injection issue):
1. openssl req -x509 -newkey rsa:2048 -nodes -days 30 -keyout selfsigned.pem -out selfsigned.pem -subj "/CN=gpt-proxy.unitree.com"
2. Redirect the upstream hostname to the attacker host (production: router-side DNS hijack; lab equivalent: /etc/hosts entry on the researcher-owned device)
3. Run the fake upstream on port 6080 (answers frames automatically within the 3-second window)
4. Trigger one conversation turn (voice command or App message)
Expected on fixed firmware: TLS handshake failure. Measured (2026-09-02): the robot connected to the attacker host, delivered a prompt frame containing its serial number and model=gpt-4.1, executed the attacker-supplied function_call frame and acknowledged it ("perform success"). Pass criterion depends only on the prompt frame and ack receipts. Optional second check: a finish frame containing a python-style shake_hands() code block drives a visible handshake gesture - a benign demonstration that forged model output controls robot behavior.
[EVIDENCE]
Attacker-side session logs, the self-signed certificate fingerprint (SHA-256 F3:B8:F1:3B:...:2C, subject=issuer - cannot pass any CA validation), device-side source extracts (byte-identical SHA-256 across the 1.1.4 package, the tested device, and the x.x.x.x package), device process/system info, hosts snapshot, and a demonstration video (web-panel full-chain recording: handshake segment = this flaw alone; red-eye segment = chain with the companion submission) are available to moderators on request. All materials are kept private pending coordinated disclosure.
[VENDOR NOTIFICATION]
Yes - vendor-first disclosure completed:
- 2026-09-03: full report + evidence package emailed to [email protected] (portal outage), then resubmitted via the Unitree SRC portal, ticket #616 (17:48 CST)
- 2026-09-07: vendor replied that the issue has already been submitted by someone else
- 2026-09-08: follow-up email (duplicate scope, fixed version, CVE status); no reply as of 2026-09-18
[CVE REQUEST]
We request CVE assignment. The vendor stated that the issue had previously been reported by another researcher (ticket #616), but no CVE identifier, public advisory, or fixed version was provided. Please perform duplicate/CNA coordination before assigning a new identifier. We have not requested IDs from any other CNA for this issue.
[RELATED SUBMISSION]
A companion submission for a command-injection flaw in the same component (set_volume value into a root shell, CWE-78, vendor ticket #474) is being submitted simultaneously. The two flaws are independently fixable (this one is fixed entirely in the TLS context construction); please do not merge them into one entry.
Credit: Junye Xiong (Xiong Junye), Sichuan University |
|---|
| Пользователь | JasperXJY (UID 101367) |
|---|
| Представление | 18.09.2026 13:54 (1 месяц назад) |
|---|
| Модерация | 24.10.2026 11:18 (1 month later) |
|---|
| Статус | принято |
|---|
| Запись VulDB | 426094 [Unitree Robotics Unitree Go2 до 1.1.13/1.1.14.1/1.1.15.1 chat_go websocket.py WebSocketClient.connect слабая аутентификация] |
|---|
| Баллы | 17 |
|---|