integrations / package-proxy

Package Proxy

Thinkst Package Proxy enforces install-time policy for npm, pip, uv, and cargo (minimum package age, upload-method regression, allow and block lists). Attestd adds a live check against confirmed compromise data, one call per unique package@version.

Package Proxy is built by Thinkst Applied Research. See their announcement post and GitHub repository. This guide patches your own Package Proxy fork after Thinkst's deploy button clones it into your account.

overview

Layered install-time defense

Package Proxy catches behavioral signals at install time. Attestd contributes confirmed compromise intelligence via GET /v1/check. The layers are complementary.

LayerWhat it catchesSource
Age check (10 days)Fresh malicious versionsPackage Proxy
Upload-method regressionMaintainer account compromise publishesPackage Proxy
Attestd compromise checkConfirmed malware / backdoor versionsAttestd API
prerequisites

What you need

  • Package Proxy deployed from your own fork (Cloudflare Worker). See the Thinkst deploy button.
  • An Attestd API key, Solo tier or above. Free tier's 60/min limit is not viable for fleet-wide installs.
  • wrangler CLI for the KV cache namespace and API key secret.
setup

Add the compromise check to your Package Proxy fork

Hook the Attestd check into file-download handlers, immediately after Package Proxy's existing static blocklist. Static blocklist first (free, instant). Attestd second (one cached call per unique package@version).

  1. Create a KV namespace for the Attestd response cache.
    bash
    npx wrangler kv namespace create attestd-cache
    # Add the returned id beside PACKAGE_PROXY_CONFIG in wrangler.jsonc:
    # "kv_namespaces": [
    #   { "binding": "PACKAGE_PROXY_CONFIG", "id": "..." },
    #   { "binding": "ATTESTD_CACHE", "id": "<id from create>" }
    # ]
  2. Set the API key as a Worker secret.
    bash
    npx wrangler secret put ATTESTD_API_KEY
  3. Extend Package Proxy's Env interface so TypeScript knows about the secret and KV binding.
    typescript
    // In src/index.ts, extend the existing Env interface:
    export interface Env {
      AUDIT_TRACKER: DurableObjectNamespace;
      PACKAGE_PROXY_CONFIG: KVNamespace;
      install_logs: D1Database;
      ASSETS: Fetcher;
      ATTESTD_API_KEY: string;
      ATTESTD_CACHE: KVNamespace;
    }
  4. Add the shared helper as src/attestd.ts.
    typescript
    // src/attestd.ts - shared helper, imported by npm.ts and pypi.ts
    // Keep this type separate from index.ts to avoid a circular import.
    export interface AttestdEnv {
      ATTESTD_API_KEY: string;
      ATTESTD_CACHE: KVNamespace;
    }
    
    export async function isAttestdCompromised(
      env: AttestdEnv,
      ecosystem: "npm" | "pypi",
      product: string,
      version: string,
    ): Promise<boolean> {
      const cacheKey = `attestd:${ecosystem}:${product}@${version}`;
      const cached = await env.ATTESTD_CACHE.get(cacheKey);
      if (cached === "1") return true;
      if (cached === "0") return false;
    
      const url = new URL("https://api.attestd.io/v1/check");
      url.searchParams.set("product", product);
      url.searchParams.set("version", version);
      url.searchParams.set("ecosystem", ecosystem);
    
      let compromised = false;
      try {
        const res = await fetch(url.toString(), {
          headers: { Authorization: `Bearer ${env.ATTESTD_API_KEY}` },
        });
        if (res.ok) {
          const body = (await res.json()) as {
            supply_chain?: { compromised?: boolean } | null;
          };
          compromised = body.supply_chain?.compromised === true;
        }
        // Non-OK response: fail open. An Attestd outage must not block installs.
      } catch {
        // Network error: fail open.
      }
    
      await env.ATTESTD_CACHE.put(cacheKey, compromised ? "1" : "0", {
        expirationTtl: 300,
      });
      return compromised;
    }
  5. Patch handleNpmFetch in src/npm.ts.
    typescript
    // After the existing block-list check in handleNpmFetch (src/npm.ts):
    import { isAttestdCompromised } from "./attestd";
    
    if (Params.env && (await isAttestdCompromised(Params.env, "npm", pName, pVer))) {
      console.log(`Attestd: ${pName}@${pVer} is a confirmed compromised version -- returning 404`);
      fireWebhook(
        Params.config.webhookUrl,
        `npm:${pName}@${pVer}`,
        "Attestd flagged this version as a confirmed supply chain compromise.",
      );
      return [new Response("Package/version not found", { status: 404 }), pName, pVer];
    }
  6. Patch handlePypiFetch in src/pypi.ts.
    typescript
    // After the existing block-list check in handlePypiFetch (src/pypi.ts):
    import { isAttestdCompromised } from "./attestd";
    
    if (Params.env && (await isAttestdCompromised(Params.env, "pypi", pName, pVer))) {
      console.log(`Attestd: ${pName}@${pVer} is a confirmed compromised version -- returning 404`);
      fireWebhook(
        Params.config.webhookUrl,
        `pypi:${pName}@${pVer}`,
        "Attestd flagged this version as a confirmed supply chain compromise.",
      );
      return [new Response("Package/version not found", { status: 404 }), pName, pVer];
    }
  7. Redeploy.
    bash
    npx wrangler deploy

Fail open on API errors and timeouts. Package Proxy's age and upload-method checks still apply. Only an explicit supply_chain.compromised === true response blocks the install. An Attestd outage must not become an install outage.

Hard rule: block only when supply_chain.compromised === true. Do not block on risk_state alone. A critical CVE is not the same as a malicious publish.

Example GET /v1/check response for a compromised version:

json
{
  "product": "litellm",
  "version": "1.82.7",
  "supported": true,
  "risk_state": "critical",
  "risk_factors": [
    "active_exploitation",
    "remote_code_execution",
    "no_authentication_required",
    "internet_exposed_service",
    "patch_available",
    "supply_chain_compromised"
  ],
  "actively_exploited": true,
  "remote_exploitable": true,
  "authentication_required": false,
  "patch_available": true,
  "fixed_version": null,
  "confidence": 0.5,
  "cve_ids": [
    "CVE-2026-33634",
    "CVE-2026-35029",
    "CVE-2026-35030",
    "CVE-2026-40217",
    "CVE-2026-42203",
    "CVE-2026-42208",
    "CVE-2026-42271",
    "CVE-2026-47101",
    "CVE-2026-47102",
    "CVE-2026-49468",
    "CVE-2026-59819",
    "CVE-2026-59820",
    "CVE-2026-59822"
  ],
  "max_epss": 0.8942,
  "supply_chain": {
    "compromised": true,
    "sources": ["osv"],
    "malware_type": "malware",
    "description": "Malicious code in litellm (PyPI)",
    "advisory_url": "https://github.com/BerriAI/litellm/issues/24518",
    "compromised_at": "2026-03-24T11:15:14Z",
    "removed_at": null,
    "source_published_at": "2026-03-24T11:15:14Z",
    "observed_at": "2026-04-18T16:49:23.317491Z",
    "ingested_at": "2026-04-18T16:49:23.317491Z",
    "first_served_at": "2026-08-03T15:34:51.347440Z",
    "provenance": null
  },
  "supply_chain_monitored": true
}
verify

Confirm a blocked version

First confirm the API reports the version as compromised, then confirm the patched Worker returns 404 for that version.

bash
curl -sS "https://api.attestd.io/v1/check?product=litellm&version=1.82.7&ecosystem=pypi" \
  -H "Authorization: Bearer $ATTESTD_API_KEY" | jq '.supply_chain.compromised'
# -> true
bash
pip download litellm==1.82.7 --index-url "https://$USER@$PACKAGE_PROXY_HOST/pypi/" --no-deps
# -> 404 / "Package/version not found" once the patch is deployed
scope

What this covers

The check covers confirmed supply chain compromise (malware, backdoors, account-takeover publishes), the same signal the production API returns as supply_chain.compromised. Newly registered compromises are covered immediately. There is no sync lag.

It does not cover CVE age, EPSS, or CISA KEV active exploitation for install policy. Use Attestd in CI or via the supply chain API for those signals.

related