Releases: matteo-sung/lockvet
Release list
lockvet v0.4.0
lockvet audit — vet what you pin right now, not a change
Everything lockvet did so far explained a diff. lockvet audit answers the
other question — "is anything we currently depend on known-bad?" — the one
you ask after supply-chain-attack news, on a codebase you just inherited, or
as a nightly hygiene check.
$ lockvet audit # in sharkdp/fd
Cargo.lock (crates.io · 126 packages)
• anyhow 1.0.102 (direct) (5mo old)
▲ affected by RUSTSEC-2026-0190 Unsoundness in `Error::downcast_mut()`
• crossbeam-epoch 0.9.18 via ignore › crossbeam-deque (2y old)
▲ affected by RUSTSEC-2026-0204 Invalid pointer dereference in `fmt::Pointer` impl…
• proc-macro-error2 2.0.1 via jiff › … › defmt-macros (23mo old)
▲ affected by RUSTSEC-2026-0173 proc-macro-error2 is unmaintained
audited 126 packages across 1 lockfile · 24 direct, 102 transitive · 3 advisories affecting 3 packages
- Walks the tree (skipping
node_modules,vendor,.git, …), reads every
lockfile in all 30 formats (SBOMs included), and shows only findings. - Flags, per pinned version: known advisories (OSV.dev,
MAL-*
malicious-package advisories included), versions missing from their
registry's index while siblings are listed — the shape of an
unpublished/pulled malicious release (a lockfile still pinning Sept 2025's
chalk@5.6.1trips both flags), deprecated / retracted / yanked /
abandoned pins with upstream reasons, and pins published only days
ago (⏱-fresh-days). - Composes like diff mode:
-md,-json,-only "@babel/*",
-fail-on vuln,unlisted,…, and-sarif— audit alerts say "is pinned
at" and anchor to the exact lockfile line, so a scheduled workflow keeps
Code Scanning honest between dependency PRs (recipe in the README). - Also available as the MCP
audittool, so your coding agent can answer
"are we affected by yesterday's npm attack?" with data. - Transition-based signals (⚙ install scripts added, ⛨ provenance
dropped) stay diff-only: an audit reports state, not history.
False-positive fixes (found by audit's full-tree coverage, affected diff mode too)
go.modreplacedirectives are now honoured. Replaced modules —
the monoreporequire sibling v0.0.0+replace => ../pathpattern — no
longer get unlisted flags or advisories matched against thev0.0.0
sentinel, which sits below every advisory's fixed range and previously
attracted the module's complete historical advisory list. Auditing
grafana/grafana: 282 → 57 advisories, 85 → 0 unlisted flags.- yarn
npm:alias descriptors (wrap-ansi-cjs@npm:wrap-ansi@^7.0.0)
no longer produce unlisted flags for the alias name, which doesn't exist
on the registry.
Install: brew install matteo-sung/tap/lockvet · go install github.com/matteo-sung/lockvet@v0.4.0 · docker run ghcr.io/matteo-sung/lockvet:0.4.0 · more options
lockvet v0.3.19
Conan support — lockfile format #30
conan.lock (C/C++) now gets the full lockvet treatment:
- Both lockfile generations parse: Conan 2 flat lockfiles
(requires/build_requires/python_requires/config_requires)
and Conan 1 graph locks — whose node graph gives direct/via …origin
labels. References pinned with a user/channel are marked non-registry
and never checked against ConanCenter. - Release ages and the ⏱ cooldown flag straight from ConanCenter
(the livecenter2.conan.ioremote — the frozen legacy remote stopped
receiving versions in 2024 and would misdate everything recent). A
version is dated by its oldest recipe revision, so recipe re-exports
don't make five-year-old releases look fresh.-fail-on freshgives
C/C++ diffs a one-flag cooldown gate. - Deliberately no unlisted claims: a Conan reference doesn't record
which remote it came from, and real projects layer private remotes over
ConanCenter for the same package names (XRPLF/rippled pins
benchmark/1.9.5alongside its own remote). Absence from ConanCenter
proves nothing, so lockvet says nothing. - OSV's
ConanCenterecosystem is queried too — near-empty today, so
advisories surface automatically as it fills in. Markdown output links
package names to conan.io/center recipe pages. - The browser playground parses and classifies
conan.lockdiffs but
skips the registry layer (ConanCenter sends no CORS headers).
Validated on the real lockfile histories of XRPLF/rippled and
memgraph/memgraph (45 commit replays, zero failures, zero noise).
New demo
The Sept 2025 chalk+debug npm takeover, replayed during its two-hour live
window — before any advisory existed:
docs/supplychain-demo.gif
lockvet v0.3.18
lockvet v0.3.18 — JSR joins the registry lineup
jsr: packages in deno.lock had no OSV ecosystem and no deps.dev
coverage — their diffs carried zero registry data until now. jsr.io itself
fills the gap (registry lineup: npm · PyPI · crates.io · RubyGems ·
Packagist · NuGet · Hex · Go · Pub · CocoaPods · Terraform · Maven · JSR):
- Release ages and the ⏱ cooldown flag from each version's
createdAt
in the package'smeta.json— the exact document Deno resolves against. - Yanked versions and archived packages land in the deprecation lane
(● deprecated upstream: version yanked on jsr.io). - Registry-verified unlisted detection. JSR never lets publishers
delete versions — yanking keeps them listed inmeta.json— so an
incoming version missing while the package's other versions ARE listed
is a strong scrubbed-release signal. - Verified changelog links: the GitHub repository each package links
on jsr.io feeds the tag-verified compare links and-changelogsrelease
notes, and markdown output links JSR package names to their jsr.io pages. - Two anonymous GETs per changed package against CORS-open endpoints — the
identical route works native and in the
browser playground. - JSR publishes are sigstore-signed across the board (no unattested
baseline to fall from), so provenance-drop detection honestly does not
apply; jsr.io keeps no per-release license history, so that check is
skipped there too. - OSV.dev queries are no longer issued for
jsr:names (npm's OSV
ecosystem cannot know them); JSR advisories will light up once OSV grows
a JSR ecosystem.
Full changelog: https://github.com/matteo-sung/lockvet/blob/main/CHANGELOG.md
v0.3.17 — Maven registry signals: relocations, verified unlisted, ages
Maven joins the registry lineup
Twelfth registry: gradle.lockfile diffs (and Maven packages in SBOMs) now
get signals from the Maven repositories themselves — Central, falling back
to Google's Maven repository, where the androidx world lives.
-
Relocation stubs land in the deprecation lane. A bump onto a POM
whose<distributionManagement><relocation>points at new coordinates
is flagged with those coordinates and the author's message:↑ mysql:mysql-connector-java 8.0.29 → 8.0.33 patch (3y old) ● deprecated upstream: relocated to com.mysql:mysql-connector-j — MySQL Connector/J artifacts moved to reverse-DNS compliant Maven 2+ coordinates.deps.dev has no relocation concept, so these were invisible before.
-
Registry-verified unlisted detection. The ▲
not in registry index
flag is settled by the repository's own per-version POM: a version
Central or Google serves loses the flag (deps.dev can lag by days), a
version both 404 on keeps it. -
Release-age backfill from the POM's
Last-Modifiedupload time for
versions deps.dev hasn't indexed yet, so the ⏱ cooldown flag works on
freshly cut Java releases too.
One anonymous CDN GET per introduced group:artifact version — the same
files every mvn/gradle build resolves against — deduplicated across
lockfiles, 8-way concurrent, with the winning host remembered per package.
Neither host sends CORS headers, so the browser playground keeps the
deps.dev-only layer for Maven (like RubyGems).
Full Changelog: https://github.com/matteo-sung/lockvet/blob/main/CHANGELOG.md
v0.3.16 — Terraform/OpenTofu registry signals
lockvet v0.3.16 — Terraform/OpenTofu providers join the registry lineup
Neither OSV nor deps.dev has any Terraform system, so until now
.terraform.lock.hcl diffs were explained with no registry data at all.
lockvet now asks the Terraform and OpenTofu registries directly:
-
Release ages + ⏱ cooldown flag from the registries' per-version
publish times. Dependabot/Renovate provider bumps show how old the
incoming release is;-fail-on freshgates them. -
Deprecation lane: providers the registry warns about, providers
delisted from registry.terraform.io, providers blocked by the OpenTofu
registry (block reason included), and HashiCorp's archived providers
with their suggested replacement:↑ hashicorp/template 2.1.2 → 2.2.0 minor (5y old) ● deprecated upstream: This provider has been archived. Please use the `templatefile` function or the `Cloudinit` provider instead -
Registry-verified unlisted detection. The registry's version-list
endpoints hard-cap at 500 entries (the AWS provider has more), so a
version absent from the list is re-checked against the per-version
endpoint and only flagged after the registry itself answers 404. That
matters: HashiCorp pulledhashicorp/aws5.71.0 after a bad release —
the GitHub tag still exists, and a lockfile pinning it gets the ▲ flag.
It was the only flag raised in a 162-commit replay of three real infra
repos' lockfile history. See the new
case study 6. -
Verified changelog links and
-changelogsfor providers, via the
source repository the registry reports. -
Routing follows the lockfile: default-host providers →
registry.terraform.io;registry.opentofu.org/…pins →
api.opentofu.org; custom/private registry hosts are left alone. -
Playground: registry.terraform.io sends no CORS headers, so the
browser build gets ages + changelog links from the CORS-open OpenTofu
mirror — and, because a mirror can lag, makes no unlisted or
deprecation claims there.
Registry lineup: npm · PyPI · crates.io · RubyGems · Packagist · NuGet ·
Hex · Go · Pub · CocoaPods · Terraform/OpenTofu.
Install: brew install matteo-sung/tap/lockvet · scoop bucket add matteo-sung https://github.com/matteo-sung/scoop-bucket && scoop install lockvet · go install github.com/matteo-sung/lockvet@v0.3.16 · docker run ghcr.io/matteo-sung/lockvet:0.3.16 · install.sh / binaries
lockvet v0.3.15
CocoaPods joins the registry lineup
npm · PyPI · crates.io · RubyGems · Packagist · NuGet · Hex · Go · Pub · CocoaPods — and this one fills the biggest blank spot yet: neither OSV nor deps.dev has a CocoaPods system, so until now Podfile.lock diffs were explained with no registry data at all. lockvet now reads the registry the same way pod install does:
-
Registry-verified unlisted detection from the sharded CDN index (
all_pods_versions_*.txt— the exact file CocoaPods resolves against): an incoming version missing while the pod's other versions are listed is what a deleted or moderated release looks like.-fail-on unlistedgates it. -
Release ages and the ⏱ cooldown flag from the trunk API's per-version publish timestamps.
-
Deprecated pods land in the deprecation lane with the podspec's named successor — a live catch:
↑ Fabric 1.7.12 → 1.7.13 patch (direct) (7y old) ● deprecated upstream: deprecated on CocoaPods; in favor of FirebaseCrashlytics -
License changes old → new from the two versions' podspecs, and the upstream repo from
source.gitfeeds the tag-verified changelog/compare-link layer (-changelogsshows Alamofire release notes; Firebase's monorepo links resolve).
Podfile.lock parsing got the full treatment while at it:
- Via-chains: pod bumps now say
(direct)orvia Firebase › FirebaseCorelike npm and Cargo diffs do, from the PODS requirement graph + DEPENDENCIES roots.-only <pod>follows the chains. - NonRegistry exemptions: pods pinned from git/path (
EXTERNAL SOURCES) or served by a private specs repo are exempt from registry checks — Signal-iOS's git-pinnedLibSignalClientstays quiet, no false flags.
The browser playground reads the CDN through its CORS-open jsDelivr mirror (trunk sends no CORS headers, so in-browser pod reports carry no ages).
Validated on 70 real Podfile.lock commits across Signal-iOS and Artsy/eigen: 0 failures, 0 false unlisted flags.
Install / upgrade: brew upgrade lockvet · scoop update lockvet · go install github.com/matteo-sung/lockvet@v0.3.15 · binaries below · docker pull ghcr.io/matteo-sung/lockvet:0.3.15
lockvet v0.3.14
pub.dev joins the registry lineup — full metadata for Dart & Flutter
deps.dev has no Pub system, so until now pubspec.lock diffs had OSV
vulnerability data but no release metadata at all. Like Packagist for
PHP and hex.pm for the BEAM world, pub.dev itself now is the metadata
layer (one anonymous GET per changed package to its CORS-open packages
API — the browser playground
uses the identical route):
- Release ages + the ⏱ cooldown flag from each version's publish
timestamp —-fail-on freshnow gates Dart bumps too. - Discontinued packages land in the deprecation lane with the
publisher's named replacement:
● deprecated upstream: discontinued on pub.dev; replaced by flutter_markdown_plus
(live catches:flutter_markdown,js, the retiredmacros
experiment). Retracted versions — onesdart pubrefuses to newly
resolve — flag the same way (live:dio5.8.0,riverpod2.3.9).
-fail-on deprecatedgates both. - Registry-verified unlisted detection (▲): pub.dev never deletes a
version outside moderation takedowns — retraction keeps it listed — so
a version missing while its siblings are listed is real signal. - Verified changelog/compare links: the upstream repo comes from the
package's pubspec; monorepo/tree/…paths reduce to the repo, and
Flutter-monorepo tags likeshared_preferences_android-v2.4.6resolve
to exact tag-to-tag diffs. - Git / path / SDK / private-host packages are marked NonRegistry —
forked plugins pinned from GitHub (AppFlowy pinspermission_handler
that way) are exempt instead of raising phantom flags.
Fixed: + build metadata ordered wrong (Dart +N, Debian +dfsg-N)
0.5.1+10 → 0.5.1+11 was rendered as a DOWNGRADE in every previous
release: semver's spec ignores build metadata, so the two parsed equal
and fell into the downgrade branch. Registries that put + in lockfiles
order it — Dart numerically, Debian repacks by revision — and lockvet now
does too: +N bumps classify as the patch-level upgrades they are.
Full changelog: https://github.com/matteo-sung/lockvet/blob/main/CHANGELOG.md
lockvet v0.3.13
lockvet v0.3.13
The Go module proxy joins the registry lineup (npm · PyPI · crates.io ·
RubyGems · Packagist · NuGet · Hex · Go). Two anonymous GETs per changed
module against proxy.golang.org — the same endpoints go get uses.
GOPROXY is honoured (private proxies work; off/direct disables the check).
- Retractions with the author's rationale: a bump onto a retracted
version lands in the deprecation lane with the rationale comment from
the module's latest go.mod (retracted: https://github.com/klauspost/compress/issues/1114), including
retractions deps.dev hasn't re-indexed.-fail-on deprecatedgates them. // Deprecated:module notices caught where deps.dev misses them
(live: go.mongodb.org/mongo-driver → "Use go.mongodb.org/mongo-driver/v2
instead").- Registry-verified unlisted: the proxy never removes a cached version,
so absence-while-siblings-exist is real signal — and brand-new tags no
longer raise false ▲ alarms (they get their ⏱ age instead). - Fresh-tag ages from
@v/{version}.info; pseudo-versions parse their
embedded commit time locally (no request). - Renamed-repo guard: a redirected repo serves the new module's go.mod,
whose directives are never applied to the old path. - proxy.golang.org sends ACAO:* — the browser playground gets every signal.
lockvet v0.3.12
lockvet v0.3.12 — Hex registry signals: the BEAM world gets its metadata layer
deps.dev has no Hex system, so until now Elixir and Gleam diffs had
vulnerability data but nothing else — no ages, no deprecations. Like
Packagist for PHP, hex.pm isn't a double-check here: it is the
metadata layer. One anonymous GET per changed package against hex.pm's
CORS-open packages API (so the browser playground
gets every signal too):
-
Release ages and the ⏱ cooldown flag from each release's
inserted_at—-fail-on freshnow works formix.lockand Gleam's
manifest.toml. -
Retired releases land in the deprecation lane with the
maintainer's reason and message:↑ httpotion 3.1.0 → 3.2.0 minor (4y old) ● deprecated upstream: retired: deprecated — Not really maintained, please check out Tesla -
Registry-verified unlisted detection — hex.pm deletes releases only
in the first hour after publish (or by admin action against malware),
so an incoming version missing from the index while the package's other
versions are listed earns the ▲ flag. -
Verified changelog links — the upstream repo from the package's
hex.pm links powers tag-to-tag compare links and-changelogs. -
Hex keeps no per-release license history, so license-change detection
is honestly skipped for this ecosystem.
Also in this release:
- Renamed forks resolve correctly:
mix.lock's map key is the OTP
application name; the Hex package name is the atom after:hex.
"chatterbox": {:hex, :ts_chatterbox, …}now reports (and queries
OSV/hex.pm for)ts_chatterbox— fixing phantom ▲ flags and advisories
matched against the wrong package's versions. - Private Hex repos and Gleam git/path packages are exempt from all
registry judgments.
Registry lineup: npm · PyPI · crates.io · RubyGems · Packagist · NuGet · Hex.
Validated on 75 real mix.lock commits across plausible/analytics,
livebook and supabase/realtime: 0 failures, 0 false unlisted flags.
lockvet v0.3.11
NuGet joins the registry lineup
npm · PyPI · crates.io · RubyGems · Packagist · NuGet. One anonymous
GET per changed package against the registration index — the same
metadata endpoint dotnet restore reads, CORS-open, so the
browser playground gets every
signal too.
Unlisted, the way NuGet itself means it
NuGet is the one registry where "unlisted" is a native concept, and
lockvet now splits the flag the way NuGet does:
- a stable version absent from the registration index entirely — what
an admin-deleted (malicious) package looks like — keeps the ▲
unlistedflag, registry-verified; - a version its author merely
unlisted
(listed:false: hidden from search, still restorable) lands in the
deprecation lane instead; - absent prereleases are cleared rather than flagged — on NuGet those
are overwhelmingly CI-feed daily builds (Roslyn nightlies and friends)
thatpackages.lock.jsoncannot attribute to their real feed. The
deps.dev-only layer used to false-flag them; this release removes a
false-positive class instead of adding one.
Deprecations with the replacement deps.dev drops
↑ WindowsAzure.Storage 9.3.2 → 9.3.3 patch (7y old)
● deprecated upstream: legacy; use Azure.Storage.Common instead
deps.dev relays only the bare reason ("Legacy"); the registration index
carries the suggested replacement package, so lockvet now shows it.
Also
- Release-age backfill from registration
publishedtimes when
deps.dev lags, so the ⏱ cooldown flag works on brand-new NuGet
releases (the 1900-01-01 sentinel NuGet stores for unlisted versions
is ignored). - License-change fallback from per-version
licenseExpressionwhen
deps.dev lacks either side. - Packages with long version histories page their registration index;
lockvet fetches only the pages whose version range covers a version
the diff actually mentions.
Validated against real Dependabot PRs and 81 historical
packages.lock.json commits across five repos: zero failures, zero
false unlisted flags.
Install: brew install matteo-sung/tap/lockvet · scoop bucket add matteo-sung https://github.com/matteo-sung/scoop-bucket && scoop install lockvet · go install github.com/matteo-sung/lockvet@v0.3.11 · docker run ghcr.io/matteo-sung/lockvet:0.3.11 · install.sh / binaries below