Unauthenticated gRPC pickle deserialization gives RCE in LeRobot
TL;DR - LeRobot's async inference pipeline calls pickle.loads() directly on bytes received over unauthenticated, unencrypted gRPC. Any caller who can reach the PolicyServer port can send a crafted SendPolicyInstructions request and execute arbitrary code on the server. Validated against 0.4.3. No patch at time of disclosure.
What happened
LeRobot is Hugging Face's open-source robotics framework. Its async inference path connects a PolicyServer to robot clients over gRPC, exchanging policy configuration, observations, and actions. That channel has no TLS and no authentication.
CVE-2026-25874 is a textbook unsafe deserialization bug (CWE-502). The server deserialises incoming bytes fields with pickle.loads() before doing anything else. pickle is not a data format - it is a code execution format. Reaching it over an unauthenticated network socket means the inference endpoint and an RCE endpoint are the same thing.
The exploitable call sites are in src/lerobot/async_inference/policy_server.py and src/lerobot/async_inference/robot_client.py. Three gRPC methods are directly reachable:
| gRPC method | Attacker controls | Where pickle.loads() runs | Impact |
|---|---|---|---|
SendPolicyInstructions | PolicySetup.data | Server | Server RCE |
SendObservations | Observation.data stream | Server | Server RCE |
GetActions | Actions.data stream | Client (if server is compromised) | Client RCE |
The GetActions path is particularly sharp: compromise the server first, then pivot to every robot client that connects to it.
The report was validated against lerobot 0.4.3. At publication, the GitHub Advisory Database listed affected and patched versions as unknown - meaning no confirmed fix is available. Public issue huggingface/lerobot#3047 and a linked PR track upstream remediation work.
This is the same failure mode that keeps hitting ML and robotics stacks. Swap pickle for something that cannot execute code, or keep it well behind a trust boundary. Leaving it on an open gRPC port achieves neither.
Who is impacted
- Any deployment running LeRobot's async inference components (
PolicyServer,robot_client) where the gRPC port is reachable from untrusted networks. - Teams running inference services on shared lab networks, cluster subnets, or exposed VPC segments where lateral movement from a single RCE is realistic.
- Client environments that connect to a server an attacker controls - the
GetActionspath turns server compromise into client compromise.
What to do now
- Track the upstream fix. Watch
huggingface/lerobot#3047and the linked PR for a patched release that removespicklefrom the async inference path. - Until a patch ships, treat the
PolicyServergRPC port as a pre-auth RCE surface:- restrict network access using security groups, firewall rules, or VPN-only access
- avoid running the service on hosts that hold high-value credentials or broad cloud permissions
- Inventory your exposure:
- find every place
PolicyServerruns - containers, dev workstations, GPU boxes, CI runners used for demos - confirm whether any
add_insecure_port()listener is reachable outside your intended trust boundary
- find every place
- If you suspect compromise, assume attacker code execution on the service host: isolate the host, review inbound gRPC traffic if logged, and rotate credentials accessible from that environment.
Related
Training
- Injection TodaySQL, NoSQL, ORM, and LLM injection - what's changed and what hasn't.
- Secure Defaults in Modern FrameworksHow Rails, Next.js, Django, and Spring protect you - and where they don't.
- Input Validation and Schema EnforcementValidate early, validate strictly - schemas, allowlists, and type-safe boundaries.
Content is AI-assisted and reviewed by our team, but issues may be missed and best practices evolve rapidly, send corrections to [email protected]. Always consult official documentation and validate key implementation decisions before making design or security choices.
