Skip to main content
Credential Harvester Disguised as Python DependencyIncident
4 min readFor Security Engineers

Credential Harvester Disguised as Python Dependency

On December 20, 2024, developers installing LiteLLM versions 1.82.7 or 1.82.8 from PyPI unknowingly turned their workstations into credential extraction engines. The TeamPCP threat actor had compromised these packages, and within hours, malicious code was running on thousands of developer machines.

What Happened

TeamPCP published two malicious versions of LiteLLM to PyPI. The compromised code scanned developer file systems for credentials, API keys, and authentication tokens stored in plaintext. GitGuardian's analysis of 6,943 affected machines revealed 33,185 unique secrets harvested from developer environments.

The attack spread through transitive dependencies. 1,705 PyPI packages automatically pulled the compromised LiteLLM versions as dependencies. If you installed any of those packages, you got the malware without ever typing "LiteLLM" in your requirements.txt.

Timeline

December 20, 2024: TeamPCP publishes compromised LiteLLM 1.82.7 and 1.82.8 to PyPI.

Within hours: Automated dependency pulls begin distributing malicious code to developer machines across organizations.

Post-discovery: GitGuardian forensics team analyzes compromised endpoints and quantifies the secret exposure.

Current status: Malicious versions removed from PyPI, but secrets already exfiltrated remain compromised.

Which Controls Failed

Endpoint protection didn't detect the malicious code. The attack ran in userspace as a legitimate Python process. Your EDR saw a developer running pip install, exactly what it expects to see.

Secrets were stored in plaintext on disk. Configuration files, environment variable dumps, shell history, and cached credentials sat unencrypted. The malware didn't need to break anything, it just read files.

Dependency verification was missing. Organizations pulled packages from PyPI without checksum verification or signature validation. No control existed to detect when a package changed owners or introduced new network behaviors.

Developer machines had production credentials. The 33,185 secrets included database connection strings, cloud provider keys, and service account tokens. Developers had everything needed to reach production systems.

No runtime monitoring for developer endpoints. When Python scripts started scanning the filesystem and opening network connections to attacker infrastructure, nothing flagged the behavior as anomalous.

What Standards Require

PCI DSS v4.0.1 Requirement 8.3.2 mandates strong cryptographic storage for authentication credentials. Those plaintext secrets in ~/.aws/credentials and .env files violate this requirement if they can access cardholder data environments.

NIST 800-53 Rev 5 SC-12 requires cryptographic key establishment and management. Storing API keys and service tokens in plaintext fails this control. You need hardware-backed key storage or encrypted secret stores with access controls.

ISO/IEC 27001:2022 Annex A.8.24 addresses use of cryptography. Developer machines holding production secrets must encrypt those credentials at rest, with keys stored separately from the encrypted data.

SOC 2 Type II CC6.1 covers logical and physical access controls. If developer machines can access production systems without additional authentication layers, you're failing separation of duties and least privilege principles.

NIST CSF v2.0 PR.DS-1 calls for protecting data at rest. Every secret on a developer machine is data at rest. If your developers can cat a file and see a production database password, you don't have protection.

Lessons and Action Items

Treat developer machines as untrusted endpoints, not trusted workstations. They run arbitrary code daily. They install dependencies from public repositories. They're compromised until proven otherwise.

Your action: Implement hardware security modules or TPM-backed secret stores on developer machines. macOS Keychain, Windows Credential Manager, or Linux Secret Service API with TPM integration. No plaintext secrets on disk, period.

Enforce dependency verification before installation. Don't blindly trust PyPI, npm, or any package repository. Supply chain attacks work because we assume packages don't change.

Your action: Set up a private package mirror that verifies checksums and signatures before making packages available internally. Tools like Sonatype Nexus or JFrog Artifactory can proxy public repositories with verification rules. Block direct access to public package indexes from developer machines.

Rotate credentials immediately after any dependency compromise. The secrets exfiltrated in this attack remain valid until you rotate them. Attackers have them permanently.

Your action: Build an automated credential rotation workflow triggered by security events. When you detect a compromised dependency, your system should enumerate affected machines, identify which secrets they had access to, and rotate those credentials within hours, not days.

Separate developer access from production access. Developers don't need production database credentials on their laptops. They need access to development environments that approximate production without holding real data or real credentials.

Your action: Implement just-in-time access for production systems. Developers request temporary credentials through a privileged access management system, use them for a specific task, and the credentials expire automatically. HashiCorp Vault, AWS IAM roles with temporary credentials, or CyberArk can enforce this model.

Monitor developer machine behavior for anomalies. When a Python process starts reading every file in a home directory and opening connections to unfamiliar IP addresses, that's detectable.

Your action: Deploy osquery or similar endpoint telemetry on developer machines. Write detection rules for filesystem enumeration patterns and unexpected network connections from development tools. You won't catch every attack, but you'll catch the obvious scanning behavior.

Audit what secrets exist on developer machines right now. You can't protect what you don't know about. GitGuardian found 33,185 secrets on 6,943 machines, an average of nearly five secrets per machine. What's the count in your environment?

Your action: Run GitGuardian's ggshield or TruffleHog across developer machines to enumerate exposed secrets. Document what you find, rotate everything, then implement controls to prevent plaintext storage going forward.

The LiteLLM compromise wasn't sophisticated. It didn't exploit a zero-day or bypass advanced security controls. It worked because developer machines had secrets in plaintext and no verification prevented malicious code from running. Fix those two problems, and this entire class of attack becomes much harder to execute.

Topics:Incident

You Might Also Like