escrow

module
v1.10.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 2, 2026 License: MIT

README ΒΆ

πŸ”’ escrow

A supply-chain firewall for your package managers. escrow sits between your developers (or CI) and the public registries β€” npm, PyPI, Go, Cargo, NuGet, Maven/Gradle, Composer β€” and won't hand over a package until it has passed your policy: a minimum age, a clean OSV vulnerability record, a known publisher. One static binary, seven ecosystems, a real-time dashboard in the browser and the terminal.

Release License Go Platforms Ecosystems Single binary

developer / CI  β†’  escrow proxy  β†’  upstream registry
                         β”‚
                   policy engine
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
           age          osv       publisher Β· popularity

A package that fails policy is removed from the manifest before the tool ever sees it β€” not an error a --force can override, just a version that appears not to exist. Blocked events surface in the dashboard, where an operator approves with one click. And because new CVEs land every day, escrow keeps re-scanning what you already pulled and flags anything that turned vulnerable after the fact.

npm PyPI Go Cargo NuGet Maven / Gradle Composer
βœ… βœ… βœ… βœ… βœ… βœ… βœ…

Real-time operator console β€” light/dark, color-blind-safe β€” and a full terminal UI (escrow-cli tui) for the same views over SSH.

Jump to: Why escrow? Β· Quick install Β· See it in action Β· Documentation


πŸ€” Why escrow?

Most supply-chain attacks don't exploit a clever bug β€” they ship a brand-new version of a package you already trust, from a hijacked maintainer account, and race to spread before anyone notices. By the time an advisory exists, the malware has been in node_modules for hours.

escrow's core bet is time. A version published today can't be installed through the proxy until it has aged past your threshold (say, 7 days) β€” long enough for the community, the registry, and the scanners to catch a bad release and pull it. The attacks below were all caught and removed within hours to a couple of days. With a 7-day quarantine, none would have reached a developer installing through escrow:

Incident What happened Closed by
ua-parser-js Β· Oct 2021 Hijacked maintainer account published 0.7.29 / 0.8.0 / 1.0.0 with a cryptominer + credential stealer β€” live on npm for ~4 hours πŸ—“οΈ age gate
coa & rc Β· Nov 2021 Same playbook days later: account takeover, malicious new versions, pulled within hours πŸ—“οΈ age gate
colors & faker Β· Jan 2022 Maintainer self-sabotage shipped an infinite-loop colors@1.4.44-liberty-2, breaking thousands of builds overnight πŸ—“οΈ age gate
Log4Shell Β· CVE-2021-44228 A known critical CVE in log4j-core (Maven) β€” not new, but catastrophic πŸ” OSV scan + πŸ” re-scan

The age gate closes the zero-day-malware-in-a-fresh-version window; the OSV scan and continuous re-scan close the known-CVE window β€” including CVEs disclosed after you downloaded a package. escrow is also deliberately honest about what it can't stop (postinstall hooks, typosquatting, git deps) β€” see Security model & threat coverage.

This is not "catches everything." It's a focused, layered gate over the most common and most time-sensitive attack window β€” and it tells you plainly where it doesn't reach.


πŸš€ Quick install

brew tap jverhoeks/tap
brew install escrow

brew services start escrow      # background service, auto-starts on login
# β†’ http://localhost:7888/dashboard
# credentials are printed to: $(brew --prefix)/var/log/escrow.log

Config lives at $(brew --prefix)/etc/escrow/escrow.toml; brew services restart escrow to reload. The formula also installs escrow-cli β€” the companion that routes your dev environment through the proxy, watches activity, and reloads config. See Routing traffic to escrow.

🐳 Docker
docker run -p 7888:7888 ghcr.io/jverhoeks/escrow:latest
# or, with a full debug config (all 7 ecosystems, admin / escrow):
cd docker/ && mkdir -p data && cp escrow.debug.toml data/escrow.toml && docker compose up -d
πŸ“¦ Binary
# pick your platform: darwin-arm64 Β· darwin-amd64 Β· linux-amd64
curl -L https://github.com/jverhoeks/escrow/releases/latest/download/escrow-darwin-arm64 -o escrow
chmod +x escrow && ./escrow            # binds 127.0.0.1:7888 (localhost only)
./escrow --host=0.0.0.0                # listen on all interfaces (team/CI use)

On first boot escrow generates escrow.toml with a random dashboard password and prints the credentials to stdout β€” save them.


🌐 Supported ecosystems

Ecosystem Tools Proxy URL Config key
npm npm, pnpm, yarn, bun http://localhost:7888/ npm = true
PyPI pip, uv http://localhost:7888/pypi/simple/ pypi = true
Go modules go http://localhost:7888/go/ go = true
Cargo cargo http://localhost:7888/cargo/ cargo = true
Composer composer http://localhost:7888/composer/ composer = true
NuGet dotnet, nuget http://localhost:7888/nuget/index.json nuget = true
Maven / Gradle mvn, gradle http://localhost:7888/maven2/ maven = true

β†’ Step-by-step setup for each tool: per-tool quickstarts.


πŸ“Έ See it in action

A real-time operator console β€” light/dark, color-blind-safe (icons and color), with shared Activity and Ecosystem filters β€” plus a full terminal UI for the same views over SSH.

CVEs blocked by advisory Package tree (downloaded + flagged) Terminal UI β€” live feed
CVEs Package tree TUI live

β†’ Full visual tour: dashboard & terminal UI β†’


πŸ“š Documentation

Guide What's inside
Dashboard & terminal UI Every view, light/dark, the escrow-cli tui, approve/block β€” with screenshots
Policy, scanning & lists Age gate Β· OSV Β· publisher Β· popularity Β· continuous re-scan Β· settings & hot-reload Β· allow/blocklist
Routing traffic to escrow The 4 methods: config files Β· local Β· shell/launch env Β· network redirect β€” and a coverage matrix
Security model & threat coverage What it does and doesn't protect against Β· trust pipeline Β· dashboard hardening Β· comparison
Deployment, storage & alerts TLS Β· internal mirrors Β· health Β· disk cache Β· systemd Β· S3 storage Β· webhooks
Configuration reference Every escrow.toml key, with defaults
GitHub Actions One-step CI supply-chain gate + Renovate composition
escrow-cli reference All escrow-cli commands: setup Β· config Β· status Β· tui Β· live Β· reload
Per-tool quickstarts npm Β· pnpm Β· yarn Β· bun Β· pip Β· uv Β· go Β· cargo Β· composer Β· dotnet Β· maven Β· gradle

⚑ GitHub Actions

Use escrow as a one-step supply-chain gate in any CI pipeline β€” add it before your install steps, no other changes needed:

steps:
  - uses: actions/checkout@v6

  - uses: jverhoeks/escrow@v1
    with:
      ecosystems: 'npm'
      min-days: '7'
      osv-severity: 'HIGH'

  - uses: actions/setup-node@v6
    with: { node-version: '20' }

  - run: npm install --ignore-scripts   # automatically uses the escrow registry

Escrow exports NPM_CONFIG_REGISTRY, PIP_INDEX_URL, GOPROXY, etc. so every install routes through the proxy, and caches packages in the Actions cache between runs.

β†’ Full guide, inputs/outputs, caching, and Renovate composition: docs/github-actions.md.


πŸ”¨ Building from source

git clone https://github.com/jverhoeks/escrow
cd escrow
go build -o escrow     ./cmd/escrow        # proxy server
go build -o escrow-cli ./cmd/escrow-cli    # companion CLI (macOS / Linux)
go test ./...

πŸ“„ License

MIT Β© 2026 Jacob Verhoeks

Directories ΒΆ

Path Synopsis
cmd
escrow command
escrow-cli command
escrow-cli/tui
Package tui implements `escrow-cli tui`, an interactive terminal dashboard that reads the running proxy's authenticated API (with an offline event-log fallback handled in run.go).
Package tui implements `escrow-cli tui`, an interactive terminal dashboard that reads the running proxy's authenticated API (with an offline event-log fallback handled in run.go).
internal
accesslog
Package accesslog keeps a bounded, in-memory record of HTTP requests handled by the escrow server.
Package accesslog keeps a bounded, in-memory record of HTTP requests handled by the escrow server.
dlstats
Package dlstats keeps a persistent, per-version count of how many times each package artifact has been downloaded through escrow, plus first/last timestamps.
Package dlstats keeps a persistent, per-version count of how many times each package artifact has been downloaded through escrow, plus first/last timestamps.
rescan
Package rescan periodically re-checks downloaded package versions for newly published vulnerabilities and acts on new findings (alert + optional auto-block).
Package rescan periodically re-checks downloaded package versions for newly published vulnerabilities and acts on new findings (alert + optional auto-block).
upstreamlog
Package upstreamlog keeps a bounded, in-memory record of escrow→upstream fetches.
Package upstreamlog keeps a bounded, in-memory record of escrow→upstream fetches.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL