supply chain

Supply chain integrity

Attestd monitors selected PyPI packages for malicious publishes and security-related yanks, alongside CVE-based risk. The supply_chain object in a /v1/check response is independent from risk_state (which reflects NVD-derived vulnerability data only).

Supply chain compromise is deterministic: a package version either has a known malicious publish or it does not. Signals come from three sources: the Attestd registry (human-verified), OSV malicious-package advisories, and PyPI yanks with security annotations. This means you can block deployment before running code from a compromised dependency.

Quick start

Check a PyPI package for supply chain compromise:

bash
# Check a PyPI package for supply chain compromise
curl "https://api.attestd.io/v1/check?product=langchain&version=0.1.0" \
  -H "Authorization: Bearer YOUR_API_KEY"

A safe package returns compromised: false with an empty sources array.

Example responses

Safe version

json
{
  "product": "langchain",
  "version": "0.3.0",
  "supported": true,
  "risk_state": "none",
  "supply_chain": {
    "compromised": false,
    "sources": [],
    "malware_type": null,
    "advisory_url": null,
    "compromised_at": null,
    "removed_at": null
  },
  "last_updated": "2026-02-23T18:21:30Z"
}

Compromised version

When a malicious publish is detected:

json
{
  "product": "langchain",
  "version": "0.1.0",
  "supported": true,
  "risk_state": "none",
  "supply_chain": {
    "compromised": true,
    "sources": ["registry", "osv"],
    "malware_type": "typosquatting",
    "description": "Version published by malicious actor impersonating official maintainer",
    "advisory_url": "https://osv.dev/MAL-2026-1234",
    "compromised_at": "2026-02-20T14:32:10Z",
    "removed_at": "2026-02-21T09:15:00Z"
  },
  "last_updated": "2026-02-23T18:21:30Z"
}

Using the Python SDK

Check supply chain status in your application or deployment pipeline:

python
import attestd

client = attestd.Client(api_key="YOUR_API_KEY")

# Check a PyPI package
result = client.check("langchain", "0.3.0")

# Check supply chain signal
if result.supply_chain and result.supply_chain.compromised:
    print(f"[ALERT] Malicious version detected: {result.product} {result.version}")
    print(f"Detected by: {', '.join(result.supply_chain.sources)}")
    print(f"Description: {result.supply_chain.description}")
    raise SystemExit("Do not deploy - compromised dependency")

if result.supply_chain is None:
    print(f"Note: {result.product} is not in supply chain monitoring")
    # Still check CVE risk
    if result.risk_state in ("critical", "high"):
        raise SystemExit(f"CVE risk detected: {result.risk_state}")

print(f"Safe to proceed: {result.product} {result.version}")

Scanning a requirements file

Scan all dependencies in requirements.txt for supply chain compromise before deploying:

requirements-check.py
# requirements-check.py
import attestd
import re
import sys

def parse_requirements(filename):
    """Parse requirements.txt and return list of (package, version) tuples"""
    packages = []
    with open(filename) as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith('#'):
                continue
            # Handle == and >= operators
            if '==' in line:
                pkg, ver = line.split('==')
                packages.append((pkg.strip(), ver.strip()))
            elif '>=' in line:
                pkg, ver = line.split('>=')
                packages.append((pkg.strip(), ver.strip()))
    return packages

def check_dependencies(filename, api_key):
    """Check all dependencies for supply chain compromise"""
    client = attestd.Client(api_key=api_key)
    packages = parse_requirements(filename)
    
    compromised = []
    for package, version in packages:
        try:
            result = client.check(package, version)
            
            # Check supply chain compromise
            if result.supply_chain and result.supply_chain.compromised:
                compromised.append({
                    'package': package,
                    'version': version,
                    'reason': result.supply_chain.description,
                    'sources': result.supply_chain.sources
                })
            
            # Also check CVE risk
            if result.risk_state in ("critical", "high"):
                compromised.append({
                    'package': package,
                    'version': version,
                    'reason': f"CVE risk: {result.risk_state}",
                    'cves': result.cve_ids
                })
        except attestd.AttestdUnsupportedProductError:
            # Not in attestd coverage - not necessarily bad, but alert
            print(f"[WARNING] {package} not in attestd coverage")
    
    if compromised:
        print("[ERROR] Compromised or risky packages found:")
        for item in compromised:
            print(f"  {item['package']}@{item['version']}: {item['reason']}")
        sys.exit(1)
    else:
        print(f"[OK] All {len(packages)} dependencies passed supply chain check")

Run this as part of your CI/CD pipeline with:

python requirements-check.py requirements.txt

Monitored packages

26 PyPI packages across AI/ML frameworks, data science, vector databases, web frameworks, and cloud SDKs. Use these exact PyPI slugs as the product query parameter. Click any package name to jump to examples below.

LLM / AI frameworks (11)

  • litellm (LiteLLM)
  • langchain (LangChain)
  • langchain-core (LangChain Core)
  • langgraph (LangGraph)
  • langgraph-checkpoint (LangGraph Checkpoint)
  • autogen-agentchat (AutoGen AgentChat)
  • autogen-core (AutoGen Core)
  • crewai (CrewAI)
  • transformers (HuggingFace Transformers)
  • openai (OpenAI SDK)
  • anthropic (Anthropic SDK)

Data science (5)

  • numpy (NumPy)
  • pandas (pandas)
  • scikit-learn (scikit-learn)
  • polars (Polars)
  • dask (Dask)

Vector databases (3)

  • pinecone (Pinecone)
  • qdrant-client (Qdrant Client)
  • chromadb (ChromaDB)

Web frameworks (3)

  • fastapi (FastAPI)
  • django (Django)
  • flask (Flask)

Cloud SDKs (3)

  • boto3 (boto3 (AWS))
  • google-cloud-storage (Google Cloud Storage)
  • azure-core (Azure Core SDK)

HTTP utilities (1)

  • requests (Requests)

Package-specific examples

Common supply chain checks for packages used in AI and data stacks:

LangChain (AI orchestration)

curl "https://api.attestd.io/v1/check?product=langchain&version=0.3.0" \
  -H "Authorization: Bearer YOUR_API_KEY"

Requests (HTTP dependency)

curl "https://api.attestd.io/v1/check?product=requests&version=2.31.0" \
  -H "Authorization: Bearer YOUR_API_KEY"

NumPy (data science)

curl "https://api.attestd.io/v1/check?product=numpy&version=1.24.0" \
  -H "Authorization: Bearer YOUR_API_KEY"

FastAPI (web framework)

curl "https://api.attestd.io/v1/check?product=fastapi&version=0.115.0" \
  -H "Authorization: Bearer YOUR_API_KEY"

Sources

  • registry (Manually curated YAML in Attestd's repo; fastest human-verified signal (confidence 1.0 when confirming a compromise).
  • osv (OSV.dev malicious-packages advisories with IDs prefixed MAL- (confidence 0.95).
  • pypi_yank (Versions yanked on PyPI with a security-related yanked_reason heuristic (confidence 0.80).

The sources array lists which sources flagged the version (e.g. ["osv", "registry"] when both agree).

Understanding the response

supply_chain: null

Product is not in supply chain monitoring. For example, infrastructure packages (nginx, postgres) or unsupported PyPI packages. This is not a safety signal. Check risk_state for CVE status.

compromised: false, sources: []

Package is monitored and no malicious publish was found at the last ingestion. Safe to use. The last_updated field shows when monitoring last ran; check this if you need the absolute latest data.

compromised: true

A malicious publish has been confirmed. Block deployment immediately. Do not auto-upgrade. Treat as an active incident. The compromised_at and removed_at timestamps indicate when the malicious version appeared and when it was pulled from PyPI.

sources

Which detection mechanisms flagged the compromise. Multiple sources (e.g., ["registry", "osv"]) mean independent confirmations. A single source like ["pypi_yank"] means the version was yanked with a security annotation.

risk_state vs supply_chain

These are independent signals. A package can have risk_state: "none" (no CVEs) but supply_chain.compromised: true (malicious publish). Always check both before deploying.

See also Response Field Reference, CI/CD Integration, Account & Portal (for scoped keys), and the Python SDK (SupplyChainSignal on RiskResult).