Skip to content

Releases: matteo-sung/lockvet

lockvet v0.4.0

Choose a tag to compare

@github-actions github-actions released this 05 Aug 22:59

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.1 trips 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 audit tool, 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.mod replace directives are now honoured. Replaced modules —
    the monorepo require sibling v0.0.0 + replace => ../path pattern — no
    longer get unlisted flags or advisories matched against the v0.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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 22:10

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 live center2.conan.io remote — 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 fresh gives
    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.5 alongside its own remote). Absence from ConanCenter
    proves nothing, so lockvet says nothing.
  • OSV's ConanCenter ecosystem 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.lock diffs 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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 20:41

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's meta.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 in meta.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 -changelogs release
    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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 19:46

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-Modified upload 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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 18:50

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 fresh gates 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 pulled hashicorp/aws 5.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 -changelogs for 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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 17:53

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 unlisted gates 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.git feeds the tag-verified changelog/compare-link layer (-changelogs shows 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) or via Firebase › FirebaseCore like 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-pinned LibSignalClient stays 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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 16:49

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 fresh now 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 retired macros
    experiment). Retracted versions — ones dart pub refuses to newly
    resolve — flag the same way (live: dio 5.8.0, riverpod 2.3.9).
    -fail-on deprecated gates 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 like shared_preferences_android-v2.4.6 resolve
    to exact tag-to-tag diffs.
  • Git / path / SDK / private-host packages are marked NonRegistry —
    forked plugins pinned from GitHub (AppFlowy pins permission_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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 15:55

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 deprecated gates 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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 14:46

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 fresh now works for mix.lock and 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

Choose a tag to compare

@github-actions github-actions released this 05 Aug 12:53

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 ▲
    unlisted flag, 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)
    that packages.lock.json cannot 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 published times 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 licenseExpression when
    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