URGENT: Python Supply Chain Attack Infecting AI Workflows

By CSharpner · March 28, 2026

There is a SERIOUS piece of malware infecting a wide range of Python software that you might be using right now. It has compromised the litellm package: a foundational library used by countless other Python packages and AI frameworks.

If you are a "vibe coder" or use AI agents, your tools may be automatically downloading, installing, and uninstalling Python packages behind the scenes. Even if the package is removed, the infection stays.

Gemini_Generated_Image_1glm9v1glm9v1glm.png

What is the damage?

This isn't just a bug; it is a full-scale credential stealer. It is designed to exfiltrate:

  • SSH Keys

  • Environment Variables (.env files)

  • Crypto Wallets

  • Cloud Tokens & K8s Secrets

How do I detect it?

I used Claude Code to research the specific indicators of compromise (IOCs) and generate detection scripts for both Windows and Linux. I am providing the full source for both here.


Linux & macOS Scanner

Save as: check-litellm-compromise.sh

#!/bin/bash
###############################################################################
# LiteLLM Supply Chain Compromise Scanner (Linux/macOS)
#
# Checks for indicators of compromise from the March 2026 TeamPCP attack
# on the litellm PyPI package (versions 1.82.7 and 1.82.8).
#
# The malicious package installs litellm_init.pth which executes on EVERY
# Python process startup and:
#   - Steals SSH keys, cloud tokens, K8s secrets, crypto wallets, .env files
#   - Installs a persistent systemd backdoor
#   - Attempts lateral movement across Kubernetes clusters
#
# Usage:
#   sudo bash check-litellm-compromise.sh                    # default: scan-dirs.json
#   sudo bash check-litellm-compromise.sh my-dirs.json       # custom config
###############################################################################
set -uo pipefail

CONFIG_FILE="${1:-$(dirname "$0")/scan-dirs.json}"
FOUND=0
LOGFILE="litellm-scan-$(date +%Y%m%d_%H%M%S).log"

log() {
    echo "$1" | tee -a "$LOGFILE"
}

log "=== LITELLM COMPROMISE SCANNER (Linux/macOS) ==="
log "Date: $(date)"
log "Config: $CONFIG_FILE"
log "Log: $LOGFILE"
log ""

# Parse project dirs from JSON config
if [ ! -f "$CONFIG_FILE" ]; then
    log "ERROR: Config file not found: $CONFIG_FILE"
    log "Create one from the sample scan-dirs.json and add your project paths."
    exit 1
fi

PROJECT_DIRS=()
while IFS= read -r dir; do
    dir=$(echo "$dir" | sed 's/^[[:space:]]*"//;s/"[[:space:]]*,\?[[:space:]]*$//')
    [ -n "$dir" ] && [[ ! "$dir" =~ ^_ ]] && PROJECT_DIRS+=("$dir")
done < <(grep -E '^\s*"/' "$CONFIG_FILE")

if [ ${#PROJECT_DIRS[@]} -eq 0 ]; then
    log "WARNING: No directories found in $CONFIG_FILE"
    log "Add your project paths to the project_dirs array."
fi

log "--- [1/11] Checking for litellm_init.pth (primary payload) ---"
RESULTS=$(find / -name "litellm_init.pth" 2>/dev/null)
if [ -n "$RESULTS" ]; then
    log "!!! INFECTED !!! Malicious file found:"
    log "$RESULTS"
    FOUND=1
else
    log "CLEAN: litellm_init.pth not found"
fi
log ""

log "--- [2/11] Checking for litellm in Python site-packages ---"
LITELLM_DIRS=$(find /usr/lib /usr/local/lib /home/*/.local/lib -type d -name "litellm" -path "*/site-packages/*" 2>/dev/null)
if [ -n "$LITELLM_DIRS" ]; then
    log "FOUND litellm installed at:"
    echo "$LITELLM_DIRS" | while read -r dir; do
        log "  $dir"
        METADATA=$(dirname "$dir")/litellm-*.dist-info/METADATA
        if ls $METADATA 2>/dev/null 1>&2; then
            VER=$(grep '^Version:' $METADATA 2>/dev/null | head -1)
            log "  $VER"
            if echo "$VER" | grep -qE '1\.82\.[78]'; then
                log "  !!! CRITICAL: This is a COMPROMISED version !!!"
            fi
        fi
    done
    FOUND=1
else
    log "CLEAN: litellm not installed in any system Python environment"
fi
log ""

log "--- [3/11] Checking .pth files for executable code ---"
SUSPICIOUS_PTH=$(find /usr/lib /usr/local/lib /home -name "*.pth" -exec grep -l 'import\|exec\|eval\|subprocess\|os\.system\|urllib\|requests' {} \; 2>/dev/null)
if [ -n "$SUSPICIOUS_PTH" ]; then
    log "WARNING: .pth files with executable code:"
    echo "$SUSPICIOUS_PTH" | while read -r f; do
        log "  $f"
        log "  --- contents ---"
        cat "$f" 2>/dev/null | while read -r line; do log "    $line"; done
    done
    FOUND=1
else
    log "CLEAN: No suspicious .pth files"
fi
log ""

log "--- [4/11] Checking for suspicious systemd services ---"
log "Recently created services (last 30 days):"
find /etc/systemd/system /home/*/.config/systemd /run/systemd/system -name "*.service" -mtime -30 2>/dev/null | grep -v '/run/systemd/generator' | while read -r svc; do
    log "  $svc ($(stat -c '%y' "$svc" 2>/dev/null | cut -d. -f1))"
done
log ""
log "User-level systemd services:"
USERSVC=$(find /home/*/.config/systemd -name "*.service" 2>/dev/null)
if [ -n "$USERSVC" ]; then
    echo "$USERSVC" | while read -r svc; do
        log "  $svc"
        grep -i 'exec' "$svc" 2>/dev/null | head -3 | while read -r line; do log "    $line"; done
    done
else
    log "  None found"
fi
log ""

log "--- [5/11] Checking cron jobs ---"
CRON_FOUND=0
for user in $(cut -d: -f1 /etc/passwd 2>/dev/null); do
    CRON=$(crontab -l -u "$user" 2>/dev/null | grep -v '^#' | grep -v '^$')
    if [ -n "$CRON" ]; then
        log "  User $user:"
        echo "$CRON" | while read -r line; do log "    $line"; done
        CRON_FOUND=1
    fi
done
[ $CRON_FOUND -eq 0 ] && log "  No cron jobs found"
log ""

log "--- [6/11] Checking SSH key integrity ---"
for homedir in /home/*; do
    user=$(basename "$homedir")
    if [ -d "$homedir/.ssh" ]; then
        log "  User: $user"
        ls -la "$homedir/.ssh/" 2>/dev/null | while read -r line; do log "    $line"; done
        if [ -f "$homedir/.ssh/authorized_keys" ]; then
            KEYCOUNT=$(wc -l < "$homedir/.ssh/authorized_keys")
            log "    authorized_keys: $KEYCOUNT entries"
        fi
    fi
done
log ""

log "--- [7/11] Checking outbound connections ---"
OUTBOUND=$(ss -tnp 2>/dev/null | grep ESTAB | grep -v '127.0.0.1\|::1\|192.168\.\|10\.\|172\.1[6-9]\.\|172\.2[0-9]\.\|172\.3[0-1]\.')
if [ -n "$OUTBOUND" ]; then
    log "Non-local outbound connections:"
    echo "$OUTBOUND" | while read -r line; do log "  $line"; done
else
    log "  No suspicious outbound connections"
fi
log ""

log "--- [8/11] Checking .env files ---"
find /home -name ".env" -type f 2>/dev/null | while read -r envfile; do
    log "  $envfile (modified: $(stat -c '%y' "$envfile" 2>/dev/null | cut -d. -f1))"
done
log ""

log "--- [9/11] Checking Docker for litellm ---"
if command -v docker &>/dev/null; then
    DOCKER_MATCH=$(docker ps -a --format "{{.Names}} {{.Image}}" 2>/dev/null | grep -i litellm)
    if [ -n "$DOCKER_MATCH" ]; then
        log "  FOUND litellm containers:"
        echo "$DOCKER_MATCH" | while read -r line; do log "    $line"; done
        FOUND=1
    else
        log "  No litellm containers"
    fi
else
    log "  Docker not installed"
fi
log ""

log "--- [10/11] Checking pip logs for litellm history ---"
for homedir in /home/* /root; do
    PIPLOGS=$(find "$homedir/.cache/pip" -name "*.log" 2>/dev/null)
    if [ -n "$PIPLOGS" ]; then
        MATCH=$(grep -li litellm $PIPLOGS 2>/dev/null)
        if [ -n "$MATCH" ]; then
            log "  FOUND litellm in pip logs for $(basename "$homedir"):"
            echo "$MATCH" | while read -r f; do
                log "    $f"
                grep -i litellm "$f" 2>/dev/null | tail -5 | while read -r line; do log "      $line"; done
            done
            FOUND=1
        fi
    fi
done
log ""

log "--- [11/11] Scanning project directories for litellm dependencies ---"
for projdir in "${PROJECT_DIRS[@]}"; do
    if [ -d "$projdir" ]; then
        log "  Scanning: $projdir"
        DIR_CLEAN=1
        REQFILES=$(find "$projdir" -maxdepth 5 \( -name "requirements*.txt" -o -name "constraints*.txt" \) -exec grep -li 'litellm' {} \; 2>/dev/null)
        if [ -n "$REQFILES" ]; then
            log "    FOUND in requirements files:"
            echo "$REQFILES" | while read -r f; do
                log "      $f"
                grep -i litellm "$f" | while read -r line; do log "        $line"; done
            done
            FOUND=1; DIR_CLEAN=0
        fi
        PYPROJECTS=$(find "$projdir" -maxdepth 5 -name "pyproject.toml" -exec grep -li 'litellm' {} \; 2>/dev/null)
        if [ -n "$PYPROJECTS" ]; then
            log "    FOUND in pyproject.toml:"
            echo "$PYPROJECTS" | while read -r f; do
                log "      $f"
                grep -i litellm "$f" | while read -r line; do log "        $line"; done
            done
            FOUND=1; DIR_CLEAN=0
        fi
        SETUPFILES=$(find "$projdir" -maxdepth 5 \( -name "setup.py" -o -name "setup.cfg" \) -exec grep -li 'litellm' {} \; 2>/dev/null)
        if [ -n "$SETUPFILES" ]; then
            log "    FOUND in setup files:"
            echo "$SETUPFILES" | while read -r f; do
                log "      $f"
                grep -i litellm "$f" | while read -r line; do log "        $line"; done
            done
            FOUND=1; DIR_CLEAN=0
        fi
        PIPFILES=$(find "$projdir" -maxdepth 5 -name "Pipfile" -exec grep -li 'litellm' {} \; 2>/dev/null)
        if [ -n "$PIPFILES" ]; then
            log "    FOUND in Pipfile:"
            echo "$PIPFILES" | while read -r f; do
                log "      $f"
                grep -i litellm "$f" | while read -r line; do log "        $line"; done
            done
            FOUND=1; DIR_CLEAN=0
        fi
        PKGJSON=$(find "$projdir" -maxdepth 5 -name "package.json" -not -path "*/node_modules/*" -exec grep -li 'litellm' {} \; 2>/dev/null)
        if [ -n "$PKGJSON" ]; then
            log "    FOUND in package.json:"
            echo "$PKGJSON" | while read -r f; do
                log "      $f"
                grep -i litellm "$f" | while read -r line; do log "        $line"; done
            done
            FOUND=1; DIR_CLEAN=0
        fi
        DOCKERFILES=$(find "$projdir" -maxdepth 5 \( -name "docker-compose*.yml" -o -name "docker-compose*.yaml" -o -name "Dockerfile" -o -name "Dockerfile.*" \) -exec grep -li 'litellm' {} \; 2>/dev/null)
        if [ -n "$DOCKERFILES" ]; then
            log "    FOUND in Docker files:"
            echo "$DOCKERFILES" | while read -r f; do
                log "      $f"
                grep -i litellm "$f" | while read -r line; do log "        $line"; done
            done
            FOUND=1; DIR_CLEAN=0
        fi
        VENVS=$(find "$projdir" -maxdepth 5 -type d -name "litellm" -path "*/site-packages/*" 2>/dev/null)
        if [ -n "$VENVS" ]; then
            log "    FOUND litellm in virtual environments:"
            echo "$VENVS" | while read -r vdir; do
                log "      $vdir"
                VMETA=$(dirname "$vdir")/litellm-*.dist-info/METADATA
                if ls $VMETA 2>/dev/null 1>&2; then
                    VER=$(grep '^Version:' $VMETA 2>/dev/null | head -1)
                    log "        $VER"
                    if echo "$VER" | grep -qE '1\.82\.[78]'; then
                        log "        !!! CRITICAL: COMPROMISED VERSION !!!"
                    fi
                fi
            done
            FOUND=1; DIR_CLEAN=0
        fi
        VENV_PTH=$(find "$projdir" -maxdepth 6 -name "litellm_init.pth" 2>/dev/null)
        if [ -n "$VENV_PTH" ]; then
            log "    !!! INFECTED !!! Malicious .pth in project:"
            echo "$VENV_PTH" | while read -r f; do log "      $f"; done
            FOUND=1; DIR_CLEAN=0
        fi
        [ $DIR_CLEAN -eq 1 ] && log "    CLEAN"
    else
        log "  SKIPPED (not found): $projdir"
    fi
done
log ""

log "==========================================="
if [ $FOUND -eq 0 ]; then
    log "  VERDICT: CLEAN"
    log "  No indicators of compromise found."
    log "==========================================="
else
    log "  VERDICT: REVIEW REQUIRED"
    log "==========================================="
    log ""
    log "Findings detected. Review the output above."
    log "If litellm versions 1.82.7 or 1.82.8 were EVER installed:"
    log "  1. Rotate ALL credentials (SSH keys, API tokens, cloud keys, DB passwords)"
    log "  2. Remove any unknown systemd services"
    log "  3. Audit outbound network connections"
    log "  4. Check for unauthorized authorized_keys entries"
    log "  5. Treat this machine as potentially compromised"
fi
log ""
log "Full log saved to: $LOGFILE"

Configuration File: scan-dirs.json
(Place in the same directory as the script.)

{
    "_comment": "Add your project directories here. The scanner will check each for litellm indicators.",
    "project_dirs": [
        "/home/youruser/Projects",
        "/home/youruser/Documents/Projects",
        "/opt/apps",
        "/var/www"
    ]
}

Windows Scanner

Save as: check-litellm-compromise.ps1

###############################################################################
# LiteLLM Supply Chain Compromise Scanner (Windows)
#
# Checks for indicators of compromise from the March 2026 TeamPCP attack
# on the litellm PyPI package (versions 1.82.7 and 1.82.8).
###############################################################################
param(
    [string]$ConfigFile = "$PSScriptRoot\scan-dirs-windows.json"
)

$ErrorActionPreference = "SilentlyContinue"
$Found = 0
$LogFile = "litellm-scan-$(Get-Date -Format 'yyyyMMdd_HHmmss').log"

function Log($msg) {
    Write-Host $msg
    Add-Content -Path $LogFile -Value $msg
}

Log "=== LITELLM COMPROMISE SCANNER (Windows) ==="
Log "Date: $(Get-Date)"
Log "Config: $ConfigFile"
Log "Log: $LogFile"
Log ""

if (-not (Test-Path $ConfigFile)) {
    Log "ERROR: Config file not found: $ConfigFile"
    Log "Create one from the sample scan-dirs-windows.json and add your project paths."
    exit 1
}

$Config = Get-Content $ConfigFile | ConvertFrom-Json
$ProjectDirs = $Config.project_dirs

Log "--- [1/9] Checking for litellm_init.pth (primary payload) ---"
$PthResults = @()
$PythonPaths = @(
    "$env:LOCALAPPDATA\Programs\Python",
    "$env:APPDATA\Python",
    "$env:ProgramFiles\Python*",
    "$env:ProgramFiles(x86)\Python*",
    "$env:USERPROFILE\.conda",
    "$env:USERPROFILE\anaconda3",
    "$env:USERPROFILE\miniconda3",
    "$env:USERPROFILE\AppData\Local\pip"
)

foreach ($path in $PythonPaths) {
    if (Test-Path $path) {
        $results = Get-ChildItem -Path $path -Recurse -Filter "litellm_init.pth" -ErrorAction SilentlyContinue
        $PthResults += $results
    }
}

foreach ($drive in (Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Used -gt 0 })) {
    $results = Get-ChildItem -Path "$($drive.Root)" -Recurse -Filter "litellm_init.pth" -Depth 10 -ErrorAction SilentlyContinue
    $PthResults += $results
}

if ($PthResults.Count -gt 0) {
    Log "!!! INFECTED !!! Malicious file found:"
    foreach ($f in $PthResults) { Log "  $($f.FullName)" }
    $Found = 1
} else {
    Log "CLEAN: litellm_init.pth not found"
}
Log ""

Log "--- [2/9] Checking for litellm in Python environments ---"
$LitellmDirs = @()
foreach ($path in $PythonPaths) {
    if (Test-Path $path) {
        $results = Get-ChildItem -Path $path -Recurse -Directory -Filter "litellm" -ErrorAction SilentlyContinue |
            Where-Object { $_.FullName -match "site-packages" }
        $LitellmDirs += $results
    }
}

if ($LitellmDirs.Count -gt 0) {
    Log "FOUND litellm installed:"
    foreach ($dir in $LitellmDirs) {
        Log "  $($dir.FullName)"
        $metadata = Get-ChildItem -Path $dir.Parent.FullName -Filter "litellm-*.dist-info" -Directory -ErrorAction SilentlyContinue
        if ($metadata) {
            $metaFile = Join-Path $metadata.FullName "METADATA"
            if (Test-Path $metaFile) {
                $version = (Get-Content $metaFile | Select-String "^Version:").Line
                Log "  $version"
                if ($version -match "1\.82\.[78]") { Log "  !!! CRITICAL: This is a COMPROMISED version !!!" }
            }
        }
    }
    $Found = 1
} else {
    Log "CLEAN: litellm not found in Python environments"
}
Log ""

Log "--- [3/9] Checking .pth files for executable code ---"
$SuspiciousPth = @()
foreach ($path in $PythonPaths) {
    if (Test-Path $path) {
        $pthFiles = Get-ChildItem -Path $path -Recurse -Filter "*.pth" -ErrorAction SilentlyContinue
        foreach ($pth in $pthFiles) {
            $content = Get-Content $pth.FullName -ErrorAction SilentlyContinue
            if ($content -match "import|exec|eval|subprocess|os\.system|urllib|requests") {
                $SuspiciousPth += $pth
            }
        }
    }
}
if ($SuspiciousPth.Count -gt 0) {
    Log "WARNING: .pth files with executable code:"
    foreach ($f in $SuspiciousPth) {
        Log "  $($f.FullName)"
        Log "  --- contents ---"
        Get-Content $f.FullName | ForEach-Object { Log "    $_" }
    }
    $Found = 1
} else {
    Log "CLEAN: No suspicious .pth files"
}
Log ""

Log "--- [4/9] Checking for suspicious services ---"
Log "Recently created services (last 30 days):"
$RecentDate = (Get-Date).AddDays(-30)
Get-WmiObject Win32_Service -ErrorAction SilentlyContinue |
    Where-Object { $_.PathName -and $_.StartMode -eq "Auto" } |
    ForEach-Object {
        $exePath = ($_.PathName -replace '"','').Split(' ')[0]
        if ((Test-Path $exePath) -and ((Get-Item $exePath).CreationTime -gt $RecentDate)) {
            Log "  $($_.Name): $($_.PathName) (created: $((Get-Item $exePath).CreationTime))"
        }
    }
Log ""

Log "--- [5/9] Checking scheduled tasks ---"
Get-ScheduledTask -ErrorAction SilentlyContinue |
    Where-Object { $_.State -eq "Ready" -and $_.Author -notmatch "Microsoft|Windows" } |
    ForEach-Object {
        $actions = ($_.Actions | ForEach-Object { "$($_.Execute) $($_.Arguments)" }) -join "; "
        Log "  $($_.TaskName): $actions"
    }
Log ""

Log "--- [6/9] Checking SSH keys ---"
$SshDir = "$env:USERPROFILE\.ssh"
if (Test-Path $SshDir) {
    Get-ChildItem $SshDir -ErrorAction SilentlyContinue | ForEach-Object { Log "  $($_.Name) (modified: $($_.LastWriteTime))" }
    $AuthKeys = Join-Path $SshDir "authorized_keys"
    if (Test-Path $AuthKeys) {
        $count = (Get-Content $AuthKeys | Measure-Object -Line).Lines
        Log "  authorized_keys: $count entries"
    }
} else {
    Log "  No .ssh directory found"
}
Log ""

Log "--- [7/9] Checking .env files ---"
$EnvFiles = Get-ChildItem -Path $env:USERPROFILE -Recurse -Filter ".env" -File -Depth 5 -ErrorAction SilentlyContinue
foreach ($envfile in $EnvFiles) { Log "  $($envfile.FullName) (modified: $($envfile.LastWriteTime))" }
Log ""

Log "--- [8/9] Checking Docker for litellm ---"
if (Get-Command docker -ErrorAction SilentlyContinue) {
    $dockerMatch = docker ps -a --format "{{.Names}} {{.Image}}" 2>$null | Select-String "litellm"
    if ($dockerMatch) {
        Log "  FOUND litellm containers:"
        foreach ($line in $dockerMatch) { Log "    $line" }
        $Found = 1
    } else { Log "  No litellm containers" }
} else { Log "  Docker not installed" }
Log ""

Log "--- [9/9] Scanning project directories for litellm dependencies ---"
foreach ($projdir in $ProjectDirs) {
    if (Test-Path $projdir) {
        Log "  Scanning: $projdir"
        $DirClean = $true
        $depPatterns = @(
            @{ Name = "requirements files"; Filters = @("requirements*.txt", "constraints*.txt") },
            @{ Name = "pyproject.toml"; Filters = @("pyproject.toml") },
            @{ Name = "setup files"; Filters = @("setup.py", "setup.cfg") },
            @{ Name = "Pipfile"; Filters = @("Pipfile") },
            @{ Name = "package.json"; Filters = @("package.json") },
            @{ Name = "Docker files"; Filters = @("docker-compose*.yml", "docker-compose*.yaml", "Dockerfile", "Dockerfile.*") }
        )
        foreach ($pattern in $depPatterns) {
            foreach ($filter in $pattern.Filters) {
                $files = Get-ChildItem -Path $projdir -Recurse -Filter $filter -Depth 5 -ErrorAction SilentlyContinue |
                    Where-Object { $_.FullName -notmatch "node_modules" } |
                    Where-Object { (Get-Content $_.FullName -ErrorAction SilentlyContinue) -match "litellm" }
                foreach ($f in $files) {
                    Log "    FOUND in $($pattern.Name): $($f.FullName)"
                    Get-Content $f.FullName | Select-String "litellm" | ForEach-Object { Log "      $($_.Line.Trim())" }
                    $Found = 1; $DirClean = $false
                }
            }
        }
        $venvLitellm = Get-ChildItem -Path $projdir -Recurse -Directory -Filter "litellm" -Depth 6 -ErrorAction SilentlyContinue |
            Where-Object { $_.FullName -match "site-packages" }
        foreach ($vdir in $venvLitellm) {
            Log "    FOUND in virtual environment: $($vdir.FullName)"
            $metadata = Get-ChildItem -Path $vdir.Parent.FullName -Filter "litellm-*.dist-info" -Directory -ErrorAction SilentlyContinue
            if ($metadata) {
                $metaFile = Join-Path $metadata.FullName "METADATA"
                if (Test-Path $metaFile) {
                    $ver = (Get-Content $metaFile | Select-String "^Version:").Line
                    Log "      $ver"
                    if ($ver -match "1\.82\.[78]") { Log "      !!! CRITICAL: COMPROMISED VERSION !!!" }
                }
            }
            $Found = 1; $DirClean = $false
        }
        $venvPth = Get-ChildItem -Path $projdir -Recurse -Filter "litellm_init.pth" -Depth 6 -ErrorAction SilentlyContinue
        foreach ($pth in $venvPth) {
            Log "    !!! INFECTED !!! Malicious .pth in project: $($pth.FullName)"
            $Found = 1; $DirClean = $false
        }
        if ($DirClean) { Log "    CLEAN" }
    } else { Log "  SKIPPED (not found): $projdir" }
}
Log ""

Log "==========================================="
if ($Found -eq 0) {
    Log "  VERDICT: CLEAN"
    Log "  No indicators of compromise found."
    Log "==========================================="
} else {
    Log "  VERDICT: REVIEW REQUIRED"
    Log "==========================================="
    Log ""
    Log "Findings detected. Review the output above."
    Log "If litellm versions 1.82.7 or 1.82.8 were EVER installed:"
    Log "  1. Rotate ALL credentials (SSH keys, API tokens, cloud keys, DB passwords)"
    Log "  2. Remove any unknown services or scheduled tasks"
    Log "  3. Audit outbound network connections"
    Log "  4. Check for unauthorized authorized_keys entries"
    Log "  5. Treat this machine as potentially compromised"
}
Log ""
Log "Full log saved to: $LogFile"

Configuration File: scan-dirs-windows.json

{
    "_comment": "Add your project directories here. The scanner will check each one for litellm indicators.",
    "project_dirs": [
        "C:\\Users\\YourUser\\Projects",
        "C:\\Users\\YourUser\\Documents\\Projects",
        "C:\\dev",
        "D:\\Projects"
    ]
}

What to do if you are infected

If the scanner returns a "REVIEW REQUIRED" verdict or identifies versions 1.82.7 or 1.82.8:

  1. Rotate ALL credentials immediately: This includes SSH keys, API tokens (OpenAI, Anthropic, AWS), and database passwords.

  2. Audit authorized_keys: Look for any public keys you did not add yourself.

  3. Wipe and Reinstall: In supply chain attacks involving persistence (like malicious .pth files), the safest path is to re-image the machine or environment.