Solutions

Keep bad packages out of your builds.

A public registry serves whatever a build asks for. A compromised release, a package squatting an internal name, or a version with a known flaw installs on your CI runner under your credentials, and the build stays green.

Why it keeps happening

Nothing between the registry and the build says no.

A build tool resolves a name to a version and installs it. The public registry answers every request the same way, whether the version was published by the maintainer or by whoever stole their publish token. Install scripts run with the runner's permissions, and the runner holds your deployment credentials.

A lockfile pins what was chosen once. It does not re-check the choice. An advisory published months after the version was cached changes nothing in the lockfile, so the build keeps passing with a known vulnerability inside it.

Internal package names are the quiet case. If a private name is not reserved, a public package of the same name can win resolution and land in the build with no error anywhere.

How we solve it

Every install passes through a registry you run, with policy in front of the cache.

Dependably Packages runs inside your perimeter, between your builds and the public registries. It proxies and caches npm, PyPI, Maven, NuGet, Cargo, Go, RPM, Alpine apk, OCI, Terraform, and Hex through one endpoint, and nothing is served until it has been verified, matched against your policy, and scanned.

Verified fetch

On a cache miss, and only for a name your organization's allow and block lists permit, the upstream artefact is fetched and checksum-verified against the digest the upstream publishes, where it publishes one. A mismatch is an audited failure and a 502, never a cached file. Publisher signatures can be verified against trust anchors you pin, for npm, PyPI, NuGet, Maven, RPM, Alpine, and Terraform.

checksum · signature

Policy gate

The staged version is matched against your policy before any catalogue row exists: licence, OSV severity, CISA KEV listing, EPSS probability, install scripts, and a minimum release age that holds a fresh publish back until it has been public long enough for a compromise to surface. A refused version is refused for every build.

policy decision

Reserved names

Your internal namespaces can be reserved on the registry, so a public package with the same name cannot be resolved by a build. Allow and block lists by package pattern cover the rest.

namespace

Daily rescan

Every cached version is scanned against the OSV database every 24 hours by default. An advisory published after a version landed still surfaces, and your severity policy is applied to the result.

OSV · daily
What you end up with

A build that can only install what you allowed.

Every fetch, policy decision, and token event is written to an append-only audit log, so whether a version ever reached a build is a query rather than a search through runner logs.

  • A refused version fails the install with the reason, at the registry, before any code runs.
  • The same decision applies to every pipeline and every developer machine pointed at the endpoint.
  • The audit log forwards to your SIEM as NDJSON over a webhook, or CEF or RFC5424 over syslog.
  • Air-gapped deployments scan what you publish against a sideloaded OSV database, with no outbound network after install.
Audit log entry
  • refused npm/example-widget@2.4.1
  • reason release age below minimum
  • token ci-main
  • forward siem-webhook · queued
Where it runs

Self-hosted, or hosted by us on request.

Dependably Packages ships as a single container image under Apache-2.0, with SQLite by default and PostgreSQL when you need HA, SAML SSO or local accounts on day one, and no phone-home. Dependably Cloud runs the same engine, the same policies, and the same audit stream on a paid plan we operate; get in touch to talk about a hosted deployment.