<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: depproof</title>
    <description>The latest articles on DEV Community by depproof (prasadv-depproof).</description>
    <link>https://dev.to/prasadv-depproof</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F14582%2F09e3ee21-09db-49ab-b841-0df9a745abd9.png</url>
      <title>DEV Community: depproof</title>
      <link>https://dev.to/prasadv-depproof</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prasadv-depproof"/>
    <language>en</language>
    <item>
      <title>Nobody left to fix it: measuring dependencies with no maintainer</title>
      <dc:creator>Prasad V</dc:creator>
      <pubDate>Wed, 23 Sep 2026 13:42:39 +0000</pubDate>
      <link>https://dev.to/prasadv-depproof/nobody-left-to-fix-it-measuring-dependencies-with-no-maintainer-6d3</link>
      <guid>https://dev.to/prasadv-depproof/nobody-left-to-fix-it-measuring-dependencies-with-no-maintainer-6d3</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://depproof.com/blog/nobody-left-to-fix-it/" rel="noopener noreferrer"&gt;the depproof blog&lt;/a&gt;.&lt;br&gt;
Measured 10 September 2026 across 24 pinned public repositories, 8,943 components, five ecosystems. Every source used is free and public.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The standard remediation for a vulnerable dependency is to upgrade it. That advice quietly assumes a maintainer exists, noticed, and shipped a release.&lt;/p&gt;

&lt;p&gt;For most packages it holds. For some it does not, and nothing in a normal findings report tells you which kind you are looking at.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number, and the argument against it
&lt;/h2&gt;

&lt;p&gt;About one component in seven in our sample carries a signal that nobody is maintaining it: &lt;strong&gt;1,202 of 8,943, or 13.4%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That figure is worth less than the split inside it, so here is the split first.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where the signal comes from&lt;/th&gt;
&lt;th&gt;Components&lt;/th&gt;
&lt;th&gt;Share of signals&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Somebody said so.&lt;/strong&gt; Deprecation flag, archived repository, published end-of-support date.&lt;/td&gt;
&lt;td&gt;242&lt;/td&gt;
&lt;td&gt;20.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;We inferred it.&lt;/strong&gt; Four years since the last release, and no repository activity either.&lt;/td&gt;
&lt;td&gt;960&lt;/td&gt;
&lt;td&gt;79.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Four signals in five are an inference from silence.&lt;/strong&gt; That is the honest shape of thismeasurement, and it is where the fair objection lives: a library can go four years without a release because it is &lt;em&gt;finished&lt;/em&gt;, not because it was abandoned. Small, single-purpose packages do exactly that.&lt;/p&gt;

&lt;p&gt;We think the inference still earns its place, for one reason. The question a maintenance signal answers is not &lt;em&gt;is this package bad&lt;/em&gt;. It is &lt;em&gt;if an advisory lands against this tomorrow, is a fix coming&lt;/em&gt;. A finished library and an abandoned one give the same answer, and it is the answer you need during an incident rather than a verdict on anybody's work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like in a real tree
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request@2.75.0
  deprecated by maintainer
  depth 4 · direct: no · scope: build and test
  advisory CVE-2023-28155 · fix version: none published
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For years this was one of the most depended-upon packages in JavaScript. Its maintainers formally deprecated it, which is a deliberate statement rather than an inference. Nobody in this project chose it: it arrives four levels down, underneath something else. The advisory against it has no fix version, because there will not be another release.&lt;/p&gt;

&lt;p&gt;There is no upgrade to recommend. The only real options are to replace whatever pulled it in, or to write down that you accept it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we measured it
&lt;/h2&gt;

&lt;p&gt;Twenty-four public repositories, pinned to fixed commits and rebuilt locally, across Maven, Gradle, npm, PyPI and Go. For every resolved component we asked three open sources what they knew:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://deps.dev/" rel="noopener noreferrer"&gt;deps.dev&lt;/a&gt; — release history and npm deprecation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ossf/scorecard" rel="noopener noreferrer"&gt;OpenSSF Scorecard&lt;/a&gt; — project activity&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://endoflife.date/" rel="noopener noreferrer"&gt;endoflife.date&lt;/a&gt; — published support windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those feed a ladder of five rules, applied in order, first match winning. The order matters: a maintainer's own declaration should outrank anything we merely observed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Kind&lt;/th&gt;
&lt;th&gt;Components&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;01&lt;/td&gt;
&lt;td&gt;The package is deprecated. The maintainer marked it so.&lt;/td&gt;
&lt;td&gt;stated&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02&lt;/td&gt;
&lt;td&gt;The repository is archived. A deliberate act, not a guess.&lt;/td&gt;
&lt;td&gt;stated&lt;/td&gt;
&lt;td&gt;125&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03&lt;/td&gt;
&lt;td&gt;This release line is past its published end of support, even where the project thrives.&lt;/td&gt;
&lt;td&gt;stated&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04&lt;/td&gt;
&lt;td&gt;Four years since the last release, and no sign of commits. Both halves required.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;inferred&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;960&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;05&lt;/td&gt;
&lt;td&gt;This particular release is deprecated, though newer ones are not.&lt;/td&gt;
&lt;td&gt;stated&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rule 4 deliberately requires &lt;em&gt;both&lt;/em&gt; an old release and a quiet repository, because release age alone marks every finished library as abandoned. Where the Scorecard has no data the second half cannot be applied and the rule falls back to release age by itself. That affected 82 of its 960 components, so roughly 9% of the largest rule rests on the weaker evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  By ecosystem
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ecosystem&lt;/th&gt;
&lt;th&gt;Carrying a signal&lt;/th&gt;
&lt;th&gt;Components&lt;/th&gt;
&lt;th&gt;Share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;852&lt;/td&gt;
&lt;td&gt;5,650&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;226&lt;/td&gt;
&lt;td&gt;1,614&lt;/td&gt;
&lt;td&gt;14.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gradle&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;756&lt;/td&gt;
&lt;td&gt;11.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maven&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;237&lt;/td&gt;
&lt;td&gt;5.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPI&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;686&lt;/td&gt;
&lt;td&gt;3.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The npm figure reflects deep transitive trees in two large JavaScript projects. The mix here is ours, not yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result worth arguing about
&lt;/h2&gt;

&lt;p&gt;The obvious way to dismiss all of this is to assume abandoned packages cluster in build and test dependencies, where nobody much cares. We can check that, because every resolved dependency carries the scope it was declared under.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reaches production&lt;/th&gt;
&lt;th&gt;Carrying a signal&lt;/th&gt;
&lt;th&gt;Components&lt;/th&gt;
&lt;th&gt;Share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ships&lt;/td&gt;
&lt;td&gt;659&lt;/td&gt;
&lt;td&gt;4,698&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build and test only&lt;/td&gt;
&lt;td&gt;372&lt;/td&gt;
&lt;td&gt;2,750&lt;/td&gt;
&lt;td&gt;13.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undetermined&lt;/td&gt;
&lt;td&gt;171&lt;/td&gt;
&lt;td&gt;1,332&lt;/td&gt;
&lt;td&gt;12.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;It does not cluster. The rate is flat.&lt;/strong&gt; Whatever causes a package to be abandoned has nothing to do with whether you ship it. Your production dependencies are not the well-tended ones. They are tended exactly as well as your test tooling, which is to say nobody checked either.&lt;/p&gt;

&lt;p&gt;The cost lands at the worst possible moment. When a critical advisory drops, the escalation runs the same way every time: someone is paged, a patch window opens, teams stop what they were doing. All of it assumes a fixed version exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result that cuts against us
&lt;/h2&gt;

&lt;p&gt;Findings concentrate more narrowly than components. 57 of 933 findings sit on a component carrying a maintenance signal, which is 6.1%. Of those, &lt;strong&gt;exactly three had no fix version published at all, and none of the three ship.&lt;/strong&gt; Two are build-and-test dependencies, one has no scope recorded. Everywhere else a newer release existed.&lt;/p&gt;

&lt;p&gt;We went looking for the acute case, a vulnerability in production with nowhere to upgrade to, and did not find it once. On this sample the maintenance signal is a statement about a project's future, not about today's remedy. Anyone quoting these numbers should quote that too.&lt;/p&gt;

&lt;h2&gt;
  
  
  And a retraction
&lt;/h2&gt;

&lt;p&gt;An earlier internal draft of this measurement reported that unmaintained components carry worse findings, with criticals running at more than three times the rate of lows. That was the headline. It does not survive a re-run.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Earlier draft&lt;/th&gt;
&lt;th&gt;Re-run&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Critical&lt;/td&gt;
&lt;td&gt;17.9%&lt;/td&gt;
&lt;td&gt;4.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;14.2%&lt;/td&gt;
&lt;td&gt;6.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;8.5%&lt;/td&gt;
&lt;td&gt;6.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;5.4%&lt;/td&gt;
&lt;td&gt;3.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Criticals now sit near the bottom of the range rather than the top, under both counting units we tried. We cannot reconstruct the earlier run to explain the difference, which is itself the lesson: &lt;strong&gt;a measurement you cannot re-run is a number you should stop quoting.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not prove
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The sample is 24 pinned open-source repositories chosen for ecosystem coverage. It is not anyone's enterprise estate.&lt;/li&gt;
&lt;li&gt;Four signals in five are inferred, and 82 of those rest on release age alone.&lt;/li&gt;
&lt;li&gt;The end-of-support rule depends on a hand-curated map from package coordinates to products and found 24 components. Treat that row as a floor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A maintenance signal is not a verdict&lt;/strong&gt; about a package or the people who wrote it. Many of these are finished libraries doing exactly what they were built to do.&lt;/li&gt;
&lt;li&gt;Scope tells you what ships, not what &lt;em&gt;runs&lt;/em&gt;. Whether a dependency ever loads at runtime would sharpen every number here, and we could not measure it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The part we have not solved
&lt;/h2&gt;

&lt;p&gt;Everyone agrees an abandoned dependency is a problem. Nobody agrees what you actually do on a Tuesday when it is four levels down, there is no fork, and the thing that pulled it in is a package you do need.&lt;/p&gt;

&lt;p&gt;Things I would genuinely like argued with in the comments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is four years the right threshold&lt;/strong&gt;, or does it depend entirely on the ecosystem?&lt;/li&gt;
&lt;li&gt;Should a deprecated &lt;em&gt;direct&lt;/em&gt; dependency read differently from a deprecated &lt;em&gt;transitive&lt;/em&gt; one,given only one of them was a decision anybody made?&lt;/li&gt;
&lt;li&gt;Is this worth surfacing at all on a package that never reaches your shipped artifact?&lt;/li&gt;
&lt;li&gt;Does the flat split between shipped and test-only match what you see, or does your estate concentrate this somewhere ours did not?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full method, the individual records and the citation block are in the &lt;a href="https://depproof.com/blog/nobody-left-to-fix-it/" rel="noopener noreferrer"&gt;original post&lt;/a&gt;. Figures and tables may be reproduced with attribution and a link back. If you re-run this against your own code and get something different, I would rather hear it than not.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>security</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
    <item>
      <title>Why npm &amp; pnpm audit miss vulnerabilities</title>
      <dc:creator>Prasad V</dc:creator>
      <pubDate>Wed, 09 Sep 2026 16:13:55 +0000</pubDate>
      <link>https://dev.to/prasadv-depproof/why-npm-pnpm-audit-miss-vulnerabilities-54j5</link>
      <guid>https://dev.to/prasadv-depproof/why-npm-pnpm-audit-miss-vulnerabilities-54j5</guid>
      <description>&lt;p&gt;You run &lt;code&gt;pnpm audit&lt;/code&gt; in CI. It prints &lt;code&gt;No known vulnerabilities found&lt;/code&gt;. The build goes green and you move on.&lt;/p&gt;

&lt;p&gt;Then someone runs &lt;code&gt;npm audit&lt;/code&gt; on the same repo, same lockfile, same afternoon — and gets a list of advisories.&lt;/p&gt;

&lt;p&gt;Neither command is broken. They disagree for the same reason a clean result from either one proves less than most teams assume, and it comes down to a single design fact about what &lt;code&gt;audit&lt;/code&gt; actually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;audit&lt;/code&gt; is a network request, not a scanner
&lt;/h2&gt;

&lt;p&gt;There is no local analysis happening. When you run &lt;code&gt;npm audit&lt;/code&gt; or &lt;code&gt;pnpm audit&lt;/code&gt;, the client sends a description of your resolved dependency tree to your configured &lt;strong&gt;registry's audit endpoint&lt;/strong&gt;, and prints the advisories that come back. That advisory data traces to the &lt;strong&gt;GitHub Advisory Database&lt;/strong&gt;, which curates known vulnerabilities for the npm ecosystem.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;audit&lt;/code&gt; is a question you ask a service about a tree you describe to it. It is not a tool reasoning over your code, and it keeps no database of its own.&lt;/p&gt;

&lt;p&gt;That one fact explains nearly every way &lt;code&gt;audit&lt;/code&gt; quietly under-delivers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four structural gaps
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. It is only as broad as one source.&lt;/strong&gt; Audit reflects the GitHub Advisory Database for npm. A vulnerability not recorded there yet, or one that lives primarily in a different database, will not&lt;br&gt;
appear no matter how carefully you run the command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. No network, no results — silently.&lt;/strong&gt; Because it depends on a reachable audit endpoint, a private registry that doesn't implement one, an air-gapped runner, or a blocking proxy can turn &lt;code&gt;audit&lt;/code&gt; into a command that returns &lt;em&gt;nothing&lt;/em&gt;. On a terminal, "didn't actually check" and "all clear" look identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. It is npm-ecosystem only.&lt;/strong&gt; Audit sees your JavaScript dependencies and nothing else. If the same repo also ships Java, Go, Python, or containers, &lt;code&gt;audit&lt;/code&gt; is silent on all of it — not because those are clean, but because they were never in scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Presence, not reachability — and no inventory.&lt;/strong&gt; Audit tells you a vulnerable version is &lt;em&gt;present&lt;/em&gt;. It can't tell you whether the vulnerable code path is ever executed, and it doesn't leave behind a machine-readable component inventory. You get a console dump, not an artifact you can re-check when the &lt;em&gt;next&lt;/em&gt; advisory drops.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why do the two disagree?
&lt;/h2&gt;

&lt;p&gt;Both hit a registry endpoint backed by the same advisory data, so the difference isn't in the answer — it's in the question. The two differ in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how each resolves and deduplicates the dependency tree&lt;/li&gt;
&lt;li&gt;whether &lt;code&gt;devDependencies&lt;/code&gt; are included in what gets described&lt;/li&gt;
&lt;li&gt;the exact state of the advisory data at the moment of each call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different views of the tree, and different timing, produce different counts.&lt;/p&gt;

&lt;p&gt;The useful conclusion is not "trust the stricter one." It's that &lt;strong&gt;a single audit number is a fragile measure of dependency risk&lt;/strong&gt; — fragile enough that two well-behaved tools reading the same&lt;br&gt;
lockfile can hand you two different stories.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a more complete check looks like
&lt;/h2&gt;

&lt;p&gt;None of this makes &lt;code&gt;audit&lt;/code&gt; useless. It makes it a &lt;strong&gt;floor&lt;/strong&gt;. If you want something sturdier, the shape matters more than the specific tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read the lockfile, not a service.&lt;/strong&gt; Resolving &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; or &lt;code&gt;package-lock.json&lt;/code&gt; locally means the check works offline, behind a private registry, and in air-gapped CI. No audit endpoint required, and no silent empty result when the network says no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check open, aggregated advisory data.&lt;/strong&gt; &lt;a href="https://osv.dev" rel="noopener noreferrer"&gt;OSV&lt;/a&gt; pulls from many sources — including GitHub Advisories and OpenSSF malicious-package data — and is built to be queried directly against a lockfile. Broader than a single source, and portable rather than proprietary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Produce an inventory.&lt;/strong&gt; Emitting a CycloneDX SBOM alongside the findings gives you something durable to re-check later. That's the difference between a one-off console dump and coverage that survives to next month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lockfile-based, open advisory data, full transitive tree, real artifact. That shape removes the network dependency, the single-source blind spot, and the missing-inventory gap in one move —&lt;br&gt;
whichever tool you get it from.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;A clean &lt;code&gt;npm audit&lt;/code&gt; is worth having. It just isn't the sentence people read it as. It says: &lt;em&gt;one advisory source, reachable at one moment, found nothing in the view of the tree it was handed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's a floor. Treat it like one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://depproof.com" rel="noopener noreferrer"&gt;depproof&lt;/a&gt;, a dependency scanner that runs on your own infrastructure. Nothing above depends on using it — the OSV-and-lockfile approach works with several tools, and the built-in &lt;code&gt;audit&lt;/code&gt; commands are a reasonable first check.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not affiliated with npm, pnpm, or GitHub; product names are used nominatively.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>security</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
