Skip to main content

Cryptographic lockfile for AI/LLM Python dependencies โ€” catches supply chain attacks before they hit prod

Project description

ailock ๐Ÿ”

Cryptographic lockfile for AI/LLM Python dependencies. Like package-lock.json, but for litellm, langchain, openai, transformers, and friends.

License: MIT CI Security Known-Bad DB Version PyPI


๐Ÿšจ Active Threat: TeamPCP Campaign (March 2026)

The supply chain campaign is active RIGHT NOW. Three ecosystems compromised in 8 days:

Date Package Versions CVE SHA256 (malicious wheel)
Mar 19 trivy-action (GitHub) 75 of 77 tags CVE-2026-33634 โ€”
Mar 24 litellm 1.82.7, 1.82.8 CVE-2026-33634 8395c326... / d2a0d5f5...
Mar 27 telnyx 4.87.1, 4.87.2 CVE-2026-33634 7321caa3... / cd081158...

ailock audit has all four malicious package hashes pre-loaded. Run it now.


The Attack

On March 24, 2026 at 10:39 UTC, two versions of LiteLLM were published to PyPI by TeamPCP after they compromised maintainer credentials via a poisoned Trivy CI scanner.

litellm 1.82.7 โ€” malicious payload embedded in proxy_server.py. Triggers on import. Three-stage attack: credential harvest (SSH keys, .env files, AWS tokens, Kubernetes secrets) โ†’ lateral movement โ†’ persistent systemd backdoor. Exfiltrates to models.litellm.cloud as tpcp.tar.gz.

litellm 1.82.8 โ€” even worse: adds litellm_init.pth to site-packages. This fires on every Python startup โ€” including pip, IDE language servers, anything. No import required.

On March 27, the stolen credentials from LiteLLM victims were used to compromise telnyx (4.87.1, 4.87.2). WAV steganography delivers platform-specific payloads from 83.142.209.203:8080.

The version number matched. The package name matched. Standard pip install --require-hashes passed โ€” because the attacker used legitimate credentials to publish malicious bytes. Only a pre-attack lockfile would have shown the hash change.

ailock verify would have caught it in CI, before it hit prod.


Install

pip install ailock

Quick Start

# 1. Generate a lockfile for your AI/LLM dependencies
ailock generate

# 2. Commit it
git add .ailock && git commit -m "chore: add ailock lockfile"

# 3. Verify in CI โ€” fails loudly if ANY hash changed
ailock verify

# 4. Check against known-bad versions database
ailock audit

How It Works

ailock generate

Scans your requirements.txt / pyproject.toml, identifies AI/LLM ecosystem packages, fetches the SHA256 hashes from PyPI's JSON API for each pinned version, and writes a .ailock lockfile:

{
  "schema_version": "1",
  "generated_at": "2024-11-15T09:41:22Z",
  "packages": {
    "litellm": {
      "version": "1.82.6",
      "hashes": [
        "sha256:a7c3f8e2b1d4..."
      ],
      "source": "pypi"
    },
    "langchain-core": {
      "version": "0.3.1",
      "hashes": [
        "sha256:f4e9a1b5c2d3..."
      ],
      "source": "pypi"
    }
  }
}

ailock verify

Re-fetches hashes from PyPI and compares. If a package's hash changed since you ran generate, that package was modified after it was released.

โœ“  All 12 packages verified โ€” integrity intact
๐Ÿšจ SUPPLY CHAIN ATTACK DETECTED

1 package has been modified since your lockfile was generated.
DO NOT deploy. Investigate immediately.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Package โ”‚ Version โ”‚ Issue                                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ litellm โ”‚ 1.82.7  โ”‚ 2 new hashes added after lockfile was generated   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ailock audit

Cross-checks your locked packages against the community known-bad.json database. Ships with the current TeamPCP campaign entries plus historical attacks:

Package Version Severity CVE Attack
litellm 1.82.7 CRITICAL CVE-2026-33634 Credential harvester + Kubernetes lateral movement
litellm 1.82.8 CRITICAL CVE-2026-33634 .pth persistence โ€” fires without any import
telnyx 4.87.1 CRITICAL CVE-2026-33634 WAV steganography payload delivery
telnyx 4.87.2 CRITICAL CVE-2026-33634 WAV steganography payload delivery
ultralytics 8.3.41 HIGH โ€” CI/CD pipeline cryptominer

Real SHA256 hashes for all malicious wheels are included. The database is fetched fresh from GitHub on each run. Community PRs welcome โ€” known-bad.json.


GitHub Actions โ€” One-Liner

- name: Verify AI/LLM dependency integrity
  run: pip install ailock && ailock verify && ailock audit

Full workflow:

name: Supply Chain Security

on: [push, pull_request]

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

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Install ailock
        run: pip install ailock

      - name: Generate lockfile (first run)
        # Only needed if .ailock doesn't exist yet
        run: |
          if [ ! -f .ailock ]; then
            ailock generate
            echo "Generated .ailock โ€” commit this file to your repo"
            exit 1
          fi

      - name: Verify package integrity
        run: ailock verify

      - name: Audit against known-bad database
        run: ailock audit

What ailock protects against

โœ… Post-release replacement attacks (the LiteLLM scenario)

Package published clean โ†’ attacker gains PyPI access โ†’ replaces the wheel with malicious code under the same version number.

ailock verify catches this because the SHA256 changes.

โœ… Known compromised versions

ailock audit cross-checks against a curated database of confirmed malicious versions. Catches packages you may have locked before the attack was public.

โœ… Typosquats with pinned versions

If you accidentally pinned langchian==0.1.0 instead of langchain, the lockfile records it โ€” and ailock audit flags known typosquats.

โŒ What it doesn't protect against

  • Packages you haven't locked (unpin them at your peril)
  • Brand new attacks not yet in the known-bad database
  • Compromised packages where the attacker maintains the same hash (very hard but possible via pre-image attacks โ€” SHA256 makes this computationally infeasible today)

Supported Package Ecosystem

ailock automatically recognises 100+ AI/LLM packages including:

LLM SDKs: litellm, openai, anthropic, cohere, mistralai, groq, replicate, together LangChain: langchain, langchain-core, langchain-community, langgraph, langsmith LlamaIndex: llama-index, llama-index-core, llama-index-llms-* HuggingFace: transformers, huggingface-hub, tokenizers, accelerate, peft, datasets Vector Stores: chromadb, pinecone-client, weaviate-client, qdrant-client Frameworks: haystack-ai, semantic-kernel, autogen, crewai, dspy Utilities: tiktoken, sentence-transformers, instructor, outlines, guidance

Use --all-packages to lock your entire dependency tree.


CLI Reference

Usage: ailock [OPTIONS] COMMAND [ARGS]...

  ailock โ€” cryptographic lockfile for AI/LLM dependencies.

Commands:
  generate  Scan AI/LLM dependencies and write a cryptographic lockfile.
  verify    Verify installed packages against .ailock cryptographic hashes.
  audit     Cross-check packages against known-bad versions database.

ailock generate

Options:
  -o, --output PATH     Output lockfile path.  [default: .ailock]
  -a, --all-packages    Include ALL packages (not just AI/LLM).
  -i, --from-installed  Use currently installed package versions.
  -f, --file PATH       Specific requirements file(s) to scan.
  --no-hashes           Skip PyPI hash fetching (faster but less secure).

ailock verify

Options:
  -l, --lockfile PATH   Path to .ailock lockfile.  [default: .ailock]
  --fail-on-missing     Exit with error if any package not on PyPI.
  --json-output         Output results as JSON (for CI integration).

ailock audit

Options:
  -l, --lockfile PATH   Path to .ailock lockfile.  [default: .ailock]
  --offline             Use only bundled database (no network call).
  --db-url TEXT         URL to known-bad JSON database.
  --json-output         Output results as JSON (for CI integration).
  --show-db             Print the full known-bad database and exit.

Contributing to the Known-Bad Database

The ailock/data/known-bad.json file is community-maintained at github.com/midnightrunai/ailock.

If you discover a compromised package version:

  1. Fork github.com/midnightrunai/ailock
  2. Add an entry to ailock/data/known-bad.json
  3. Include: package name, version, SHA256 hashes (if known), description, references
  4. Open a PR

Format:

{
  "package": "some-ai-package",
  "version": "1.2.3",
  "hashes": ["sha256:..."],
  "severity": "CRITICAL",
  "cve": "CVE-2024-XXXXX",
  "description": "What happened and why it's bad.",
  "reported_at": "2024-11",
  "references": ["https://..."]
}

Why not just use pip's built-in hash checking?

pip install --hash works but requires you to:

  1. Manually specify hashes in requirements.txt
  2. Include hashes for every package (including transitive deps)
  3. Re-generate everything on every update

ailock focuses specifically on the AI/LLM ecosystem, adds a curated known-bad database, and makes the workflow CI-native.


License

MIT โ€” see LICENSE


Built by Midnight Run โ€” the AI that builds while you sleep.

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

ailock-0.2.0.tar.gz (30.9 kB view details)

Uploaded Source

Built Distribution

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

ailock-0.2.0-py3-none-any.whl (29.3 kB view details)

Uploaded Python 3

File details

Details for the file ailock-0.2.0.tar.gz.

File metadata

  • Download URL: ailock-0.2.0.tar.gz
  • Upload date:
  • Size: 30.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for ailock-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1afe40d892ef992d11a1002fee21f9886e94d0a2383b0bdcb7280f38d0d1bb87
MD5 3d7ab42ee5fa86c1d9f2a6f5b93556fd
BLAKE2b-256 f2012098d467e1d443fb2a6fbcb1c204d869792c2b6a80d40bc9a3bf6d7c04ef

See more details on using hashes here.

File details

Details for the file ailock-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: ailock-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 29.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for ailock-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 10f4cf88d80457090c15eac0ac34daea621384f0d0a368648829bc76dae6b4d8
MD5 f2d043059a765de1aba150e52eed0344
BLAKE2b-256 44dba5b32eeb1cd32ac81f0d88ff80f0b10fef853861422fec0b5071117ad673

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