You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: vulnerabilities/the-reachy-mini-bluetooth-command-handler-is-vulnerable-to-arbitrary-root-script-execution-via-path-traversal-cve-2026-62661.md
The Reachy Mini Bluetooth command handler (BluetoothCommandService._handle_command in src/reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py) accepts a CMD_<script> payload after a successful PIN authentication and runs the matching file from the commands/ directory with sudo. The script name is taken from the BLE payload with no sanitization and combined using os.path.join("commands", script_name). On POSIX, if the second argument is an absolute path, os.path.join discards the commands/ prefix entirely, so a payload such as CMD_/tmp/reachy_pwn causes the handler to execute sudo /tmp/reachy_pwn.sh. Relative payloads such as CMD_../attacker/pwn likewise escape the intended directory. An attacker who can place a .sh file on the filesystem — for example via the unrestricted media-sounds upload (CVE-2026-55419) — can therefore run that script as root.
32
+
The Reachy Mini Bluetooth command handler (`BluetoothCommandService._handle_command` in `src/reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py`) accepts a `CMD_` payload after a successful PIN authentication and runs the matching `.sh`file from the `commands/` directory with `sudo`. The script name is taken from the BLE payload with no sanitization and combined using `os.path.join("commands", script_name)`. On POSIX, if the second argument is an absolute path, `os.path.join` discards the `commands/` prefix entirely, so a payload such as `CMD_/tmp/reachy_pwn` causes the handler to execute `sudo /tmp/reachy_pwn.sh`. Relative payloads such as `CMD_../attacker/pwn` likewise escape the intended directory. An attacker who can place a `.sh` file on the filesystem, for example via the unrestricted media-sounds upload (CVE-2026-55419), can therefore run that script as root.
33
33
34
34
This issue is the third step in a documented compromise chain: unrestricted file upload, Bluetooth authentication bypass, then this directory traversal. The published CVSS score (7.2, AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H) reflects authenticated Bluetooth access.
Python documents that an absolute second argument replaces the earlier join pieces, so `os.path.join("commands", "/tmp/reachy_pwn.sh")` evaluates to `/tmp/reachy_pwn.sh`.
46
+
36
47
## PoC
37
48
38
49
<br>
@@ -42,7 +53,7 @@ This issue is the third step in a documented compromise chain: unrestricted file
The first argument is discarded because the second argument is an absolute path.
70
+
The first argument is discarded when the second argument is an absolute path. A `../` segment also leaves `commands/`.
59
71
60
72
<br>
61
73
62
74
**Step 2 - Authenticate on the Bluetooth command characteristic**
63
75
64
76
<br>
65
77
66
-
From a BLE client (nRF Connect, Web Bluetooth, or the Reachy Mini control app), write the robot PIN as:
78
+
From a BLE client (nRF Connect, Web Bluetooth, or the Reachy Mini control app), write the robot PIN. The handler expects the `PIN_` prefix followed by the last five digits of the serial, for example:
67
79
68
80
```
69
-
PIN_<last_5_digits_of_serial>
81
+
PIN_12345
70
82
```
71
83
72
84
<br>
@@ -99,15 +111,24 @@ On a vulnerable build this resolves to `sudo /tmp/reachy_pwn.sh` instead of a fi
99
111
100
112
<br>
101
113
102
-
On a Linux checkout of reachy_mini 1.10.0 or later:
114
+
The vendor shipped `tests/unit_tests/test_ble_path_traversal.py` with the fix. On a Linux checkout of an unpatched tree, copy that test in and run:
Those tests assert that the handler never invokes sudo on a path outside `commands/`. They fail against unpatched trees (PATH TRAVERSAL: handler invoked sudo ...) and pass once the command name is constrained to a bare `[A-Za-z0-9_-]+` filename.
122
+
Expected output on a vulnerable build:
123
+
124
+
```
125
+
PATH TRAVERSAL: handler invoked `sudo ...` for payload ...
Those tests assert that the handler never invokes sudo on a path outside `commands/`. They fail while the vulnerability is present and pass once the command name is constrained to a bare `[A-Za-z0-9_-]+` filename.
0 commit comments