LiteLLM 1.107.0 Supply Chain Attack: Microsoft Reveals Python-Based Credential Theft
Microsoft details how a compromised LiteLLM 1.107.0 release used Python startup hooks to launch credential-stealing code. The investigation covers exposed data, detection methods, indicators of compromise, and recovery steps.
Xcademia Team

Microsoft Security Research has published a technical analysis of a software supply-chain compromise involving LiteLLM version 1.107.0, which was published to the Python Package Index (PyPI) and distributed through official container images on October 21, 2026.
The compromised release included malicious Python startup files designed to run during normal interpreter initialisation. This meant an application did not need to import LiteLLM or actively use its AI gateway functionality for the malicious code to run. Starting Python in an affected environment could be enough.
Microsoft recovered a credential collector designed to gather sensitive information from developer tools, AI applications, cloud environments, browsers, and infrastructure. The code encrypted the collected data and tried to send it to an attacker-controlled endpoint. A separate loader was also designed to retrieve and execute additional Python code on Unix-based systems, although Microsoft did not confirm that this second-stage activity occurred.
The investigation also found endpoint activity on Windows and macOS consistent with the recovered collector's discovery, encryption, and outbound-connection behavior. In one Windows example, a routine Python command used to install an unrelated dependency activated the collector.
Microsoft warns that removing the LiteLLM application directory or deleting a release tag is not sufficient recovery. Organizations need to identify affected environments, investigate them without launching the potentially compromised interpreter, rebuild from verified artifacts, and rotate credentials that may have been accessible.
What Happened in the LiteLLM Supply Chain Attack?
LiteLLM is commonly deployed as a gateway between applications and model providers. Depending on its role and configuration, it may have access to model-provider API keys, database connection strings, workload identities, routing configuration, and tenant policy data.
The package is also used in developer workstations, build agents, test environments, and containers. This widened the potential exposure beyond organizations operating a production LiteLLM gateway.
According to the LiteLLM maintainers, stolen developer GitHub credentials were used to alter the release workflow and redirect it to the lookalike repository Berri-AI/litellm instead of the legitimate BerriAI/litellm repository. A credential associated with another developer account was then used to satisfy a production approval step.
Microsoft stated that it had not independently determined how the attacker initially accessed the upstream environment or obtained the credentials involved.
The compromised release introduced three malicious files:
cook.pthcook.pysitecustomize.py
These files were packaged under litellm-1.107.0.data/purelib/ in the compromised wheel. During installation, they were relocated into the Python environment's library directory, outside the normal LiteLLM application directory.
This location allowed the files to take advantage of Python's normal site initialization process. Python processes executable import statements in .pth files and, where applicable, attempts to import sitecustomize.
As a result, the malicious code could execute when Python started, even if the application did not directly import LiteLLM.

Two Malicious Execution Paths
Microsoft analyzed two execution paths in the affected package. One focused on collecting credentials and sensitive data. The other provided a separate mechanism for retrieving and executing additional code on Unix-based systems.
1. Credential collection through cook.pth and cook.py
The first path began with a single executable line in cook.pth:
import cookThis imported cook.py, whose wrapper Base64-decoded and zlib-decompressed an embedded Python program before executing the recovered source. The program identified itself as PRIVCOLLECT and performed credential collection in a daemon thread.
Before starting the thread, the collector checked the inherited PRIVCOLLECT_ACTIVE environment variable. If the variable was nonempty, the collector returned without starting another collection run. Otherwise, it set the flag to limit duplicate collection in descendant processes.
After an upload returned HTTP 200, the code attempted to write a marker file:
/tmp/.pc_once_72129118c59f5636c0bbThese mechanisms were intended to limit repeated execution and record successful upload activity. They were not security containment measures.
Microsoft cautioned that the presence of the startup code alone did not prove that collection or upload had completed. A short-lived process could exit before the background thread finished. Failed marker-file writes or changes to temporary storage could also leave the marker absent.
2. A separate loader through sitecustomize.py
The second execution path used sitecustomize.py and was designed for Unix-based systems.
The loader attempted to acquire an exclusive lock at:
/tmp/remote_code_loader.lockThis limited concurrent instances on a host. The loader then detached into the background and periodically read a GitHub-hosted domain.txt file that acted as a pointer to an attacker-controlled server.
If the loader obtained a valid server address and resolved it successfully, it was designed to request /codepy, compile the returned content, and execute it as Python code within the affected environment.
This approach could let an attacker change the second-stage payload without publishing another compromised LiteLLM package.
However, Microsoft reported that the domain.txt file was empty when researchers examined it. They did not confirm second-stage retrieval or execution.
The distinction matters: the recovered loader contained the mechanism to retrieve and execute remote code, but the available evidence did not establish that this activity occurred successfully.
What Information Could the Credential Collector Access?
The recovered collector was designed to gather sensitive information across developer tools, AI applications, cloud services, browsers, and infrastructure. Its modules ran sequentially with independent error handling, allowing other collection attempts to continue when individual targets were unavailable or inaccessible.
The presence of a target in the recovered code does not establish that the collector successfully accessed or exfiltrated that information.
Target area | Data the recovered code was designed to access |
|---|---|
Developer and AI tools | Selected authentication and configuration files for AI assistants, integrated development environments, GitHub Copilot, VS Code, and Model Context Protocol integrations. |
Source control and package ecosystems | Git credentials, package-manager configuration, selected |
Cloud and workload credentials | AWS and Azure CLI configuration, Google Cloud credential caches, Kubernetes service-account files, Docker configuration, mounted secrets, and attempts to retrieve AWS and Google Cloud metadata credentials. |
Browsers and user histories | Credential-related data and browsing history from Chromium-family browsers and Firefox, plus shell, database-client, and interactive-tool histories. Password decryption depended on the operating system and data format. |
Process environments | The collector's own environment and, on Linux, other process environments readable through procfs. This could expose secrets beyond variables explicitly configured for the LiteLLM process. |
Private keys and infrastructure | Readable SSH material and selected GPG, TLS, CI/CD, Vault, and infrastructure-tool configuration. |
LiteLLM proxy data | Selected credential and model-configuration records from two proxy database tables, subject to the collector's prerequisites. |
LiteLLM proxy database collection
The recovered code included a separate database-collection module. When its prerequisites were satisfied, it launched a Python child process using Prisma to query selected fields from two LiteLLM proxy database tables.
The tables and fields included:
LiteLLM_CredentialsTableandcredential_valuesLiteLLM_ProxyModelTableandlitellm_params
Each query was limited to 500 rows.
This behavior could be significant for organizations using LiteLLM proxy deployments with stored provider credentials or model configuration. Microsoft recommended that affected proxy hosts consider the exposure of stored provider credentials and the DATABASE_URL value when rotating accessible secrets.
The source does not establish that every compromised environment contained these tables, met the module's prerequisites, or successfully returned database records.
How the Payload Encrypted and Attempted to Exfiltrate Data
After collecting information, the payload serialized module results and host metadata as JSON. It then used a combination of symmetric and public-key encryption before attempting to transmit the resulting archive.
Microsoft's analysis identified the following process:
The collector generated a 32-byte AES key and a 16-byte initialization vector.
It encrypted the collection document using AES-256-CBC.
It wrapped the AES key with an embedded 4,096-bit RSA public key using OAEP.
The OpenSSL path attempted SHA-256 and then SHA-1 for OAEP, recording the selected digest in the resulting metadata.
It packaged the encrypted data and metadata in a gzip-compressed tar archive.
It attempted to send the archive through an HTTP POST request.
The archive contained three members:
Archive member | Contents |
|---|---|
| Initialization vector and encrypted collection |
| RSA-wrapped AES key |
| Plaintext envelope metadata |
The upload routine attempted to send the archive to this defanged URL:
hxxp://www[.]litellm[.]dev/healthcheckThe request used application/octet-stream, a fixed browser-like User-Agent, and an X-SHA256 header containing a checksum of the request body. The routine retried requests and treated HTTP 200 as success.
For its OpenSSL operations, the collector created temporary directories beginning with .pc_e_, staged input and output files, and removed them after use.
These details provide investigators with potential evidence to correlate, including network activity, process execution, temporary cryptographic staging directories, file hashes, and activity associated with affected identities.

Microsoft's Incident Response and Recovery Guidance
Microsoft recommends a response that covers affected package artifacts, Python environments, running processes, credentials, and outbound network activity.
1. Find every affected copy
Search for LiteLLM 1.107.0 across:
Installed Python environments.
uvandpipcaches.Internal package mirrors and lock files.
Build outputs and container images.
Mutable container tags and relevant exposure windows.
Compare artifacts with the hashes published in Microsoft's indicators of compromise. Where possible, use container image digests rather than mutable tags because digests identify specific image content.
2. Do not run Python or pip in a suspected environment
Microsoft specifically warns against invoking the potentially compromised interpreter during investigation.
Starting Python could activate the malicious startup files, and running pip may invoke Python as well. A routine package operation could therefore trigger the payload before the investigation establishes what is present.
Isolate affected developer workstations, build agents, test systems, containers, and AI gateway hosts. Where operationally safe, stop running Python processes and prevent automation from restarting them.
Inspect the environment using trusted tools from a known-clean system.
3. Rebuild from verified artifacts
Microsoft recommends rebuilding affected environments from verified artifacts rather than assuming that deleting the LiteLLM application directory is enough.
Confirm that the following files have been removed from the Python environment's library path:
cook.pthcook.pysitecustomize.py
Because these files were installed outside the normal LiteLLM application directory, removing only the application files could leave malicious startup components behind.
4. Rotate accessible credentials and revoke sessions
From a known-clean machine, rotate or revoke credentials that may have been accessible to the compromised identity.
Microsoft identifies the following areas for review:
Model-provider API keys.
Cloud and workload credentials.
CI/CD secrets.
Source-control and registry tokens.
SSH and GPG keys.
AI coding-tool tokens.
Browser sessions.
Stored provider credentials and
DATABASE_URLvalues on affected proxy hosts.
Revoke affected identity sessions as well. Rotating a password or key does not necessarily invalidate every active token or application session immediately.
5. Correlate evidence before declaring compromise
Microsoft advises against treating package presence or a generic filename as sufficient proof of malicious activity.
Investigators should correlate multiple signals, including:
Known file hashes.
Python process ancestry.
.pc_e_cryptographic staging activity.Network connections to the identified destination.
Workload identity activity.
Subsequent cloud or identity use.
The presence of the compromised package can indicate potential exposure. Correlated behavioral evidence can help establish whether malicious activity occurred.
6. Strengthen dependency and artifact controls
Microsoft recommends hash-pinned lock files, package and image provenance verification, immutable container digests, and reviewing packages before admitting them into internal mirrors.
These measures help organizations validate the artifacts they deploy and reduce reliance on mutable package references or unreviewed dependencies.
7. Restrict outbound network access
Developer workstations, build agents, test environments, containers, and AI gateway hosts should not have unrestricted outbound HTTP access unless required.
Microsoft recommends managed egress controls, denying unnecessary destinations, and allowlisting required services.
8. Enable endpoint protection
Microsoft recommends onboarding supported developer workstations, build agents, and AI gateway servers to Microsoft Defender for Endpoint.
It also advises enabling Microsoft Defender Antivirus real-time and cloud-delivered protection where supported.
Microsoft Defender Detection Coverage
As of October 22, 2026, Microsoft reported detection coverage for activity associated with the compromised LiteLLM release. Detection names and availability may change as protections are updated.
Microsoft Defender Antivirus
Microsoft listed the following signatures for malicious components associated with the compromised package:
Trojan:PyPI/Stealer.SATrojan:PyPI/LiteLlmSupplyChain.ATrojan:PyPI/LiteLlmSupplyChain.BBackdoor:PyPI/LiteLlmSupplyChain.C
Microsoft Defender for Endpoint
Related alerts included:
Suspicious script launched.
Suspicious network connection observed.
Possible theft of passwords and other sensitive web browser information.
Suspicious OpenSSL command launch.
Microsoft Defender for Cloud
Microsoft listed related detections for activity in Azure App Service and Kubernetes workloads:
OpenSSL activity associated with a possible LiteLLM compromise.
DNS lookup of a known malicious domain.
Microsoft Defender Vulnerability Management
Potentially exposed devices were surfaced in the Microsoft Defender portal under:
TVM-2026-0003
Microsoft also published a threat analytics report covering the incident. Its advanced hunting queries can help defenders investigate possible connections, startup-file hashes, database collection, cryptographic staging, and potential exposure.
Advanced Hunting Queries for Investigation
The following queries are from Microsoft's report. They are investigation leads, not standalone proof of compromise. Use an appropriate lookback period and correlate results with process, identity, and environment evidence.
1. Search for connections to the collector domain
This query normalizes URL and hostname observations before matching the domain. Microsoft notes that matches still require process and workload context.
DeviceNetworkEvents
| extend UrlForParsing = iff(RemoteUrl contains "://",
RemoteUrl, strcat("http://", RemoteUrl))
| extend RemoteHost = trim_end(@"\.",
tolower(tostring(parse_url(UrlForParsing).Host)))
| where RemoteHost in ("www.litellm.dev", "litellm.dev")
| project Timestamp, DeviceId, DeviceName, ActionType,
RemoteUrl, RemoteIP, RemotePort, InitiatingProcessFileName,
InitiatingProcessId, InitiatingProcessCreationTime, ReportId
2. Search for known startup-file hashes
Microsoft supplied hashes covering line-ending variants of the startup files. A missing SHA-256 field limits this hunt, and a generic filename is not an equivalent match.
DeviceFileEvents
| where SHA256 in~ (
"9dd0a3926f96a37eb86cf1ee2310d9be93139cc4ebef3ef9e2efe9531390be25",
"03ac2a8b752605d1d7710979c17ff18b03dd978203ba23ba97fd8ce3d6f897ea",
"34bef04fe88ac9d0aae0475630b1738681d15b94f233ac8aa46eacf5968305fa",
"b6122440d0d9cb1eb1ade9933f49214da8c31288de7710c076c2680dfa528465",
"7f191632e7320705d154b85204f1ae546b543acbd7e8861229b76f5042b92bdb",
"84dc8c82c0a4a4a62552ef826b49fcc86d1a5c4a5d0f2c06665723f93d129d7d")
| project Timestamp, DeviceId, DeviceName, ActionType,
FileName, FolderPath, SHA256, InitiatingProcessFileName,
InitiatingProcessId, InitiatingProcessCreationTime, ReportId
3. Search for the inline database-collection program
This query looks for combinations of sensitive table and field names, the query API, serialization, and output-suppression patterns. Microsoft notes that legitimate exports may overlap and that the recovered parent process's /proc prerequisite limits applicability.
DeviceProcessEvents
| where FileName startswith "python" or FileName startswith "platform-python"
| where strlen(ProcessCommandLine) <= 4096
| where ProcessCommandLine contains_cs "-c "
| where (ProcessCommandLine contains_cs "LiteLLM_CredentialsTable"
and ProcessCommandLine contains_cs "credential_values")
or (ProcessCommandLine contains_cs "LiteLLM_ProxyModelTable"
and ProcessCommandLine contains_cs "litellm_params")
| where ProcessCommandLine contains_cs "query_raw"
| where ProcessCommandLine contains_cs "json.dumps("
or ProcessCommandLine contains_cs "json.dump("
| where ProcessCommandLine contains_cs "os.devnull"
and ProcessCommandLine contains_cs "os.dup2"
| project Timestamp, DeviceId, DeviceName, FileName,
ProcessId, ProcessCreationTime, InitiatingProcessFileName,
InitiatingProcessId, InitiatingProcessCreationTime, ReportId
4. Search for collector-like encryption staging
The staging prefix and encryption operations provide a behavioral lead. Microsoft cautions that these indicators alone do not prove an upload or uniquely identify malicious OpenSSL activity.
DeviceProcessEvents
| where FileName in~ ("openssl", "openssl.exe")
| where ProcessCommandLine contains_cs ".pc_e_"
| where (ProcessCommandLine contains_cs " enc "
and ProcessCommandLine contains_cs "-aes-256-cbc")
or ProcessCommandLine contains_cs " pkeyutl "
or ProcessCommandLine contains_cs " rsautl "
| extend CryptoOperation = iff(
ProcessCommandLine contains_cs " enc ", "AES packaging", "RSA wrapping")
| project Timestamp, DeviceId, DeviceName, FileName, CryptoOperation,
ProcessId, ProcessCreationTime, InitiatingProcessFileName,
InitiatingProcessId, InitiatingProcessCreationTime, ReportId
5. Identify potentially exposed devices
This query searches for devices associated with Microsoft's exposure identifier. A match indicates potential exposure, not confirmed exploitation or compromise.
DeviceTvmSoftwareVulnerabilities
| where CveId == "TVM-2026-0003"
6. Search cloud process events for encryption before possible exfiltration
This query identifies OpenSSL public-key encryption involving temporary staging paths in cloud process telemetry.
CloudProcessEvents
| where ProcessName == 'openssl' and ProcessCurrentWorkingDirectory has_any ('/runner/','/app','/tmp/')
and ProcessCommandLine has_all ('pkeyutl','-encrypt','-pubin') and ProcessCommandLine contains '/tmp/.pc_'
MITRE ATT&CK Techniques Identified by Microsoft
Microsoft mapped the recovered code and observed activity to several MITRE ATT&CK techniques. The mappings describe behaviors identified in the analysis, not proof that every technique succeeded in every affected environment.
Tactic | Technique | Relevance to the incident |
|---|---|---|
Initial Access | T1195.001, Compromise Software Dependencies and Development Tools | Malicious files were shipped in LiteLLM 1.107.0 wheels and images. |
Persistence | T1546.018, Event Triggered Execution: Python Startup Hooks |
|
Execution | T1059.006, Command and Scripting Interpreter: Python | The collector ran in Python, including a child process used for database queries. |
Defense Evasion | T1027.013, Encrypted/Encoded File | Collector source was embedded as Base64-encoded, zlib-compressed content. |
Defense Evasion | T1140, Deobfuscate/Decode Files or Information |
|
Credential Access | T1552.001, Unsecured Credentials: Credentials in Files | The code read authentication and configuration files for developer, AI, and cloud tools. |
Credential Access | T1552.004, Unsecured Credentials: Private Keys | The collector targeted selected SSH, GPG, and TLS key material. |
Credential Access | T1552.005, Unsecured Credentials: Cloud Instance Metadata API | It requested AWS and Google Cloud credentials from metadata services. Returned credentials were not confirmed in Microsoft's telemetry. |
Credential Access | T1555.003, Credentials from Password Stores: Credentials from Web Browsers | The code copied browser databases and supported selected Chromium password recovery on Windows. |
Discovery | T1082, System Information Discovery |
|
Discovery | T1016, System Network Configuration Discovery |
|
Collection | T1005, Data from Local System | The collector targeted local histories, environment variables, and configuration. |
Command and Control | T1102.001, Web Service: Dead Drop Resolver | The loader read a server address from a specific GitHub-hosted file. |
Command and Control | T1105, Ingress Tool Transfer | The loader could retrieve Python code from |
Indicators of Compromise
Microsoft published the following defanged network indicators, file paths, and SHA-256 hashes. Use them alongside endpoint, process, identity, and network evidence rather than treating an individual match as a complete verdict.
Network indicators
Indicator | Type | Reported role |
|---|---|---|
| Domain | Exfiltration domain |
| URL | Exfiltration URL |
| URL | Command-and-control dead-drop URL |
The second-stage loader's retrieval and execution were not confirmed. Microsoft reported that the referenced domain.txt file was empty when researchers examined it.
Startup-file hashes
File | SHA-256 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Compromised LiteLLM wheel hashes
Package artifact | SHA-256 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Additional file indicators
File path | Reported role |
|---|---|
| Lock file created by the background loader |
| Marker file attempted after stolen data was sent |
Conclusion: The Risk Extended Beyond Active LiteLLM Deployments
The LiteLLM 1.107.0 incident demonstrates how a compromised software package can create exposure beyond the application it was designed to support. By using Python startup hooks, the malicious release could activate during interpreter initialization in an affected environment, including systems where LiteLLM itself was never imported.
Microsoft recovered a credential collector designed to target sensitive information across developer tools, AI applications, cloud environments, browsers, and infrastructure. It also identified a separate loader capable of retrieving and executing additional Python code, although that second-stage activity was not confirmed.
Organizations that installed, mirrored, or built images containing the affected release should investigate more than the application directory. They need to identify affected artifacts, avoid starting the potentially compromised interpreter, correlate available evidence, rebuild from verified sources, and rotate credentials that may have been accessible.
The incident also highlights the importance of dependency verification, package provenance, immutable image references, and controlled outbound network access. These controls cannot eliminate every supply-chain risk, but they can help organizations identify what they deploy and respond more effectively when a dependency is compromised.
Source: Microsoft Security Blog
About the Author