JustAppSec
Back to news

Unauthenticated gRPC pickle deserialization gives RCE in LeRobot

2 min readPublished 28 Apr 2026Source: The Hacker News

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 methodAttacker controlsWhere pickle.loads() runsImpact
SendPolicyInstructionsPolicySetup.dataServerServer RCE
SendObservationsObservation.data streamServerServer RCE
GetActionsActions.data streamClient (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 GetActions path turns server compromise into client compromise.

What to do now

  • Track the upstream fix. Watch huggingface/lerobot#3047 and the linked PR for a patched release that removes pickle from the async inference path.
  • Until a patch ships, treat the PolicyServer gRPC 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 PolicyServer runs - containers, dev workstations, GPU boxes, CI runners used for demos
    • confirm whether any add_insecure_port() listener is reachable outside your intended trust boundary
  • 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


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.

Need help?Get in touch.