CVE-2026-42208: semantic-router Unbounded litellm Pin Pulls Credential-Stealing Wheel
Installing semantic-router 0.1.8 through 0.1.14 could silently pull in a backdoored version of litellm that steals every credential on the machine the moment Python starts, with no import required.
The problem
semantic-router declared litellm>=1.61.3 with no upper bound. When litellm==1.82.8 was the latest release on PyPI, a plain pip install semantic-router on any affected version resolved to that compromised wheel.
The malicious wheel shipped litellm_init.pth into site-packages/. Python's site module executes .pth file lines on every interpreter startup, so the payload fired automatically, no import litellm needed. It harvested SSH keys, cloud credentials, environment variables, Kubernetes configs, and .env files, then encrypted and exfiltrated everything to https://models.litellm.cloud/ using AES-256-CBC plus an embedded RSA public key.
Proof of concept
A working proof-of-concept for this issue in semantic-router, with the exact payload below.
# Any pip install on affected semantic-router 0.1.8-0.1.14 during the exposure window
# could silently resolve litellm==1.82.8, dropping the malicious .pth file.
pip install "semantic-router>=0.1.8,<0.1.15"
# The installed .pth file contained the launcher line (from GHSA-5mg7-485q-xm76 / issue #24512):
# import os, subprocess, sys; subprocess.Popen([sys.executable, "-c", "import base64; exec(base64.b64decode('...'))"])
# This line fired on every Python startup. The double-base64 payload collected
# credentials and POSTed a tar.gz (X-Filename: tpcp.tar.gz) to https://models.litellm.cloud/
# Verify exposure:
pip show litellm # if version is 1.82.7 or 1.82.8, treat system as compromised
find ~/.cache/uv -name 'litellm_init.pth' # check uv cache tooThe root cause in semantic-router is a missing upper bound on its litellm dependency. Pip's resolver picks the latest matching version, so litellm>=1.61.3 resolved to 1.82.8 during the roughly 40-minute window it was live on PyPI on March 24, 2026.
The malicious wheel (published by the TeamPCP threat group using stolen PyPI credentials from a prior Trivy CI/CD compromise) used Python's .pth mechanism as the trigger. Because .pth files in site-packages/ are processed by the site module at interpreter startup, the payload executed before any application code ran, on every Python invocation, not just when litellm was imported.
The payload was double-base64-encoded to evade naive grep, and the exfiltration domain litellm.cloud was chosen to resemble the legitimate litellm.ai domain.
The fix in semantic-router 0.1.15 raises the floor to litellm>=1.83.7, skipping both compromised versions. CWE-1395 (Dependency on Vulnerable Third-Party Component) and the supply chain nature of this issue map to CWE-506 (Embedded Malicious Code) as assigned.
The fix
Upgrade to semantic-router>=0.1.15, which pins litellm>=1.83.7. If you cannot upgrade immediately, add litellm>=1.83.7 as an explicit constraint in your own project. Audit every environment where an affected install ran: check pip show litellm, search for litellm_init.pth in site-packages/, and look for persistence artifacts at ~/.config/sysmon/sysmon.py and ~/.config/systemd/user/sysmon.service.
Rotate all credentials (SSH keys, AWS/GCP/Azure tokens, API keys, database passwords, Kubernetes configs) that were accessible from any affected machine.
Reported by Callum McMahon (FutureSearch) - upstream discovery; litellm maintainers - triage.
Related research
- high · 8.7CVE-2026-70492CVE-2026-70492: open-webui Stored XSS via KaTeX Render-Error Fallback
- high · 7.1CVE-2026-70485CVE-2026-70485: Open WebUI NAT64-Encoded SSRF Filter Bypass
- high · 7.7CVE-2026-70479CVE-2026-70479: open-webui SSRF via Unvalidated Sub-Resource Requests in Playwright Web Loader
- highCVE-2026-69247CVE-2026-69247: cryptography PKCS#7 EnvelopedData Bleichenbacher Oracle