<?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: hamelin123</title>
    <description>The latest articles on DEV Community by hamelin123 (@hamelin123).</description>
    <link>https://dev.to/hamelin123</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%2Fuser%2Fprofile_image%2F4035759%2Fe6c07084-858d-464e-89ce-9f964b716399.png</url>
      <title>DEV Community: hamelin123</title>
      <link>https://dev.to/hamelin123</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hamelin123"/>
    <language>en</language>
    <item>
      <title>Popular projects SHA-pin GitHub Actions 67.6% of the time — but Docker base images only 7.6%</title>
      <dc:creator>hamelin123</dc:creator>
      <pubDate>Mon, 24 Aug 2026 08:27:46 +0000</pubDate>
      <link>https://dev.to/hamelin123/popular-projects-sha-pin-github-actions-676-of-the-time-but-docker-base-images-only-76-12id</link>
      <guid>https://dev.to/hamelin123/popular-projects-sha-pin-github-actions-676-of-the-time-but-docker-base-images-only-76-12id</guid>
      <description>&lt;p&gt;Pinning a dependency to something that &lt;em&gt;can't change underneath you&lt;/em&gt; is the same idea whether it's a CI action or a container base image. We already measured how often popular projects pin their GitHub Actions to a commit SHA. So we asked the identical question one layer down: how often do they pin their Docker base images to an immutable &lt;code&gt;@sha256&lt;/code&gt; digest?&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Across &lt;strong&gt;25 popular&lt;/strong&gt; infra/app projects (&lt;strong&gt;250 external base-image references&lt;/strong&gt;), only &lt;strong&gt;7.6%&lt;/strong&gt; are pinned to an immutable &lt;code&gt;@sha256&lt;/code&gt; digest (&lt;strong&gt;19 refs&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;81.6%&lt;/strong&gt; use a mutable version tag like &lt;code&gt;node:20.1.2&lt;/code&gt; (&lt;strong&gt;204 refs&lt;/strong&gt;); &lt;strong&gt;10.8%&lt;/strong&gt; are &lt;code&gt;:latest&lt;/code&gt;/untagged (&lt;strong&gt;27 refs&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;5 of 22&lt;/strong&gt; projects that ship Dockerfiles use &lt;code&gt;@sha256&lt;/code&gt; pinning for &lt;em&gt;any&lt;/em&gt; base image.&lt;/li&gt;
&lt;li&gt;Same supply-chain principle, measured before: &lt;strong&gt;GitHub Actions pinned to a commit SHA = 67.6%&lt;/strong&gt;. That's roughly &lt;strong&gt;9× more adoption&lt;/strong&gt; for Actions than for container digests.&lt;/li&gt;
&lt;li&gt;Point-in-time (2026-07-21), reproducible across all 25 repos with public tooling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pin type&lt;/th&gt;
&lt;th&gt;Refs&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;Digest (&lt;code&gt;@sha256&lt;/code&gt;, immutable)&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;7.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version tag (&lt;code&gt;node:20.1.2&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;204&lt;/td&gt;
&lt;td&gt;81.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;:latest&lt;/code&gt; or untagged&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;10.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total external base images&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;250&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;5&lt;/code&gt; projects that digest-pin &lt;em&gt;any&lt;/em&gt; base image: posthog, Ghost, elasticsearch, moby, n8n.&lt;/p&gt;

&lt;p&gt;Side by side with the Actions study:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Immutability practice&lt;/th&gt;
&lt;th&gt;Adoption across popular repos&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions pinned to a commit SHA&lt;/td&gt;
&lt;td&gt;67.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker base images pinned to a digest&lt;/td&gt;
&lt;td&gt;7.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;FROM node:20&lt;/code&gt; (or worse, &lt;code&gt;FROM node:latest&lt;/code&gt;) pulls whatever image that tag resolves to &lt;em&gt;at build time&lt;/em&gt;. Tags are mutable — the same &lt;code&gt;node:20&lt;/code&gt; can be a different image tomorrow — so a reproducible, tamper-evident build pins to the content digest: &lt;code&gt;FROM node@sha256:…&lt;/code&gt;. It's the exact same risk that made SHA-pinning a CI checklist item after the 2025 GitHub Actions compromises (tj-actions, reviewdog) — just one layer down, and adopted ~9× less often.&lt;/p&gt;

&lt;p&gt;Our read on the gap: the Actions ecosystem had a forcing function (those compromises) plus a one-click habit (Dependabot). The base-image equivalent hasn't had its forcing function yet — and digest strings are ugly to write by hand, so most teams stop at a version tag.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fair caveat
&lt;/h2&gt;

&lt;p&gt;Version tags are &lt;strong&gt;not&lt;/strong&gt; "wrong." &lt;code&gt;node:20.1.2&lt;/code&gt; is readable, gets patch updates, and is fine for most teams. Only a &lt;code&gt;@sha256&lt;/code&gt; digest is &lt;em&gt;truly&lt;/em&gt; immutable, so we report it as the strict gold standard for reproducible/tamper-evident builds — not as a claim that everyone on a version tag is insecure. The clearly-risky category is &lt;code&gt;:latest&lt;/code&gt;/untagged, which makes builds non-reproducible and lets the base change silently. Some pinned/unpinned images are also a project's own first-party images, where the trust model differs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to pin
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# mutable — resolves at build time, can change underneath you&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.13-slim&lt;/span&gt;

&lt;span class="c"&gt;# immutable — the exact image content, human-readable tag kept in a comment&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.13.13-slim-bookworm@sha256:355bfa66770995d7e9a0da4b3473b44d0cb451f6b56f5615ad9c39e3c4eca03f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let Dependabot (&lt;code&gt;package-ecosystem: docker&lt;/code&gt;) bump the digest so you stay patched without tracking a moving tag.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Corpus:&lt;/strong&gt; 25 popular infra/app repos; 22 ship Dockerfiles with external base images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per repo:&lt;/strong&gt; sparse-checkout the Dockerfiles, parse every external base-image &lt;code&gt;FROM&lt;/code&gt; (excluding internal stage aliases, &lt;code&gt;--platform&lt;/code&gt; flags, build-args, and &lt;code&gt;scratch&lt;/code&gt;), and classify as digest, version tag, or &lt;code&gt;:latest&lt;/code&gt;/untagged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-check:&lt;/strong&gt; Shield's &lt;code&gt;CONTAINER-002&lt;/code&gt; (&lt;code&gt;:latest&lt;/code&gt;) rule against an independent &lt;code&gt;FROM&lt;/code&gt; parser — the &lt;code&gt;:latest&lt;/code&gt; counts agreed (16 vs 15, one build-stage edge case). Digest classification is unambiguous (a reference either contains &lt;code&gt;@sha256:&lt;/code&gt; or it doesn't), and we hand-verified samples at both ends.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reproduce it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &lt;span class="nt"&gt;--filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;blob:none &lt;span class="nt"&gt;--sparse&lt;/span&gt; https://github.com/grafana/grafana g
&lt;span class="nb"&gt;cd &lt;/span&gt;g &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git sparse-checkout init &lt;span class="nt"&gt;--no-cone&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git sparse-checkout &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s1"&gt;'**/Dockerfile'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git checkout
&lt;span class="c"&gt;# a base image is immutable only if the ref contains @sha256:&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rhE&lt;/span&gt; &lt;span class="s1"&gt;'^\s*FROM\s'&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*Dockerfile*'&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s1"&gt;'@sha256:'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;25 popular repos, point-in-time (2026-07-21) — not a random sample; large projects skew more disciplined, so the ecosystem-wide digest rate is plausibly lower.&lt;/li&gt;
&lt;li&gt;We classify references, not unique images; a reused base weights a repo's count.&lt;/li&gt;
&lt;li&gt;Stage aliases, &lt;code&gt;--platform&lt;/code&gt; flags and build-args are excluded; one residual cross-file alias (~0.4%) may remain and doesn't move the headline.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Full per-repo dataset, method, and the cross-study comparison are on the canonical page: &lt;strong&gt;&lt;a href="https://zennoxa.com/research/base-image-pinning-2026" rel="noopener noreferrer"&gt;Do popular projects pin their base images? We checked 25&lt;/a&gt;&lt;/strong&gt;. Zennoxa Research publishes reproducible security data on public projects with public tooling — no third-party scanner involved.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>security</category>
      <category>devsecops</category>
      <category>supplychain</category>
    </item>
    <item>
      <title>Vulnerability advisories grew 2.3x-6.6x in 5 years; open-source tool count stayed flat</title>
      <dc:creator>hamelin123</dc:creator>
      <pubDate>Fri, 21 Aug 2026 03:33:57 +0000</pubDate>
      <link>https://dev.to/hamelin123/vulnerability-advisories-grew-23x-66x-in-5-years-open-source-tool-count-stayed-flat-4a5m</link>
      <guid>https://dev.to/hamelin123/vulnerability-advisories-grew-23x-66x-in-5-years-open-source-tool-count-stayed-flat-4a5m</guid>
      <description>&lt;p&gt;We bucketed every advisory in OSV.dev's public per-ecosystem archives by its record-publication year for 11 package ecosystems, and overlaid the count of open-source, security-tagged tools per language from the analysis-tools.dev catalog. The question: is the pool of open-source tools that covers a language keeping pace with how fast advisories enter the record?&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (every number recomputes from the public archives)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Known-vulnerability advisories entering the record grew &lt;strong&gt;2.3x-6.6x over five years&lt;/strong&gt; for most ecosystems: PHP &lt;strong&gt;6.6x&lt;/strong&gt;, Java &lt;strong&gt;4.8x&lt;/strong&gt;, .NET &lt;strong&gt;4.2x&lt;/strong&gt;, Rust &lt;strong&gt;3.0x&lt;/strong&gt;, Python &lt;strong&gt;2.3x&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The open-source tool count per language is roughly &lt;strong&gt;flat&lt;/strong&gt; — it is a property of the catalog, not a curve that rises with advisory volume.&lt;/li&gt;
&lt;li&gt;The gap is a &lt;strong&gt;flow&lt;/strong&gt;: recent years (2023-2025 average) add up to &lt;strong&gt;157 new advisories per open-source tool per year for Rust&lt;/strong&gt;, 121 for PHP, 112 for Go — against just &lt;strong&gt;2-13 tools&lt;/strong&gt; per language.&lt;/li&gt;
&lt;li&gt;Across the 11 ecosystems, &lt;strong&gt;~4,900 new vulnerability advisories&lt;/strong&gt; land per year, served by &lt;strong&gt;42 catalogued open-source security tools&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm is the honest exception&lt;/strong&gt; (0.8x): its explosive growth is in malicious-package reports, which we excluded. Counting malware, npm's raw volume is &lt;strong&gt;223,802 total, 96.9% MAL-&lt;/strong&gt;; counting real vulnerable-dependency advisories, it isn't even growing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Growth: advisories entering the record per year
&lt;/h2&gt;

&lt;p&gt;Known-vulnerability advisories (malware excluded), by publication year:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ecosystem (language)&lt;/th&gt;
&lt;th&gt;2020&lt;/th&gt;
&lt;th&gt;2021&lt;/th&gt;
&lt;th&gt;2022&lt;/th&gt;
&lt;th&gt;2023&lt;/th&gt;
&lt;th&gt;2024&lt;/th&gt;
&lt;th&gt;2025&lt;/th&gt;
&lt;th&gt;Growth (2023-25 vs 2019-20)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Packagist (PHP)&lt;/td&gt;
&lt;td&gt;156&lt;/td&gt;
&lt;td&gt;430&lt;/td&gt;
&lt;td&gt;2,326&lt;/td&gt;
&lt;td&gt;771&lt;/td&gt;
&lt;td&gt;1,063&lt;/td&gt;
&lt;td&gt;712&lt;/td&gt;
&lt;td&gt;6.6x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maven (Java)&lt;/td&gt;
&lt;td&gt;151&lt;/td&gt;
&lt;td&gt;394&lt;/td&gt;
&lt;td&gt;3,009&lt;/td&gt;
&lt;td&gt;951&lt;/td&gt;
&lt;td&gt;565&lt;/td&gt;
&lt;td&gt;711&lt;/td&gt;
&lt;td&gt;4.8x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NuGet (.NET)&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;313&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;106&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;4.2x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;crates.io (Rust)&lt;/td&gt;
&lt;td&gt;168&lt;/td&gt;
&lt;td&gt;487&lt;/td&gt;
&lt;td&gt;339&lt;/td&gt;
&lt;td&gt;260&lt;/td&gt;
&lt;td&gt;321&lt;/td&gt;
&lt;td&gt;363&lt;/td&gt;
&lt;td&gt;3.0x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPI (Python)&lt;/td&gt;
&lt;td&gt;469&lt;/td&gt;
&lt;td&gt;1,417&lt;/td&gt;
&lt;td&gt;1,878&lt;/td&gt;
&lt;td&gt;849&lt;/td&gt;
&lt;td&gt;1,020&lt;/td&gt;
&lt;td&gt;1,010&lt;/td&gt;
&lt;td&gt;2.3x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RubyGems (Ruby)&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;71&lt;/td&gt;
&lt;td&gt;238&lt;/td&gt;
&lt;td&gt;91&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;67&lt;/td&gt;
&lt;td&gt;1.5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm (JavaScript)&lt;/td&gt;
&lt;td&gt;934&lt;/td&gt;
&lt;td&gt;597&lt;/td&gt;
&lt;td&gt;669&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;436&lt;/td&gt;
&lt;td&gt;632&lt;/td&gt;
&lt;td&gt;0.8x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(2026 is a partial year, inflated by an OSV ingestion wave, so we lead with complete years through 2025. Pub/Hex/Swift are omitted from the growth table — their OSV histories start ~2022 with small counts.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The flow gap: new advisories per open-source tool, per year
&lt;/h2&gt;

&lt;p&gt;Recent-years (2023-2025) average new advisories per year, against catalogued open-source tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ecosystem (language)&lt;/th&gt;
&lt;th&gt;New advisories / yr (2023-25 avg)&lt;/th&gt;
&lt;th&gt;Open-source tools&lt;/th&gt;
&lt;th&gt;New advisories / tool / yr&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;crates.io (Rust)&lt;/td&gt;
&lt;td&gt;315&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;157&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Packagist (PHP)&lt;/td&gt;
&lt;td&gt;849&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;121&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;1,342&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;112&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maven (Java)&lt;/td&gt;
&lt;td&gt;742&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;74&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPI (Python)&lt;/td&gt;
&lt;td&gt;960&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;74&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm (JavaScript)&lt;/td&gt;
&lt;td&gt;489&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NuGet (.NET)&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RubyGems (Ruby)&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The thinnest-covered ecosystems face the steepest flow. Rust adds ~157 new advisories per open-source tool per year against just 2 catalogued tools; PHP ~121; Go ~112.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;Defenders have finite triage capacity. If yearly inflow keeps climbing while the tool count per language stays flat, teams face more signal per tool and per human-hour every year. That is a structural argument for &lt;strong&gt;prioritization&lt;/strong&gt; — ranking by exploitation likelihood (EPSS, CISA KEV) and reachability — rather than trying to hand-review a growing pile. This study measures the &lt;em&gt;flow&lt;/em&gt; (how fast advisories enter each year); a companion study, The SCA Coverage Gap, measured the &lt;em&gt;stock&lt;/em&gt; (total advisories per tool).&lt;/p&gt;

&lt;h2&gt;
  
  
  How it was measured (reproducible)
&lt;/h2&gt;

&lt;p&gt;For each ecosystem we download OSV's &lt;code&gt;all.zip&lt;/code&gt;, read every advisory's &lt;code&gt;published&lt;/code&gt; RFC3339 date, bucket by 4-digit year, and exclude &lt;code&gt;MAL-&lt;/code&gt; (malicious-package) advisories so the curve tracks vulnerable-dependency advisories, not malware reports. Tool counts are the open-source, security-tagged tools per mapped language from the analysis-tools.dev catalog.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;eco &lt;span class="k"&gt;in &lt;/span&gt;npm PyPI Maven Go RubyGems crates.io NuGet Packagist Pub Hex SwiftURL&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://osv-vulnerabilities.storage.googleapis.com/&lt;/span&gt;&lt;span class="nv"&gt;$eco&lt;/span&gt;&lt;span class="s2"&gt;/all.zip"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; e.zip
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"== &lt;/span&gt;&lt;span class="nv"&gt;$eco&lt;/span&gt;&lt;span class="s2"&gt; (vulnerability advisories by year, MAL- excluded) =="&lt;/span&gt;
  unzip &lt;span class="nt"&gt;-p&lt;/span&gt; e.zip &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="s1"&gt;'*MAL-*'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-aoE&lt;/span&gt; &lt;span class="s1"&gt;'"published"[[:space:]]*:[[:space:]]*"[0-9]{4}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oE&lt;/span&gt; &lt;span class="s1"&gt;'[0-9]{4}$'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OSV data is public (per-source CC-BY-4.0 / CC0 / MIT / Apache-2.0, with attribution to OSV.dev and the underlying advisory databases); the analysis-tools.dev catalog is MIT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;p&gt;OSV's &lt;code&gt;published&lt;/code&gt; field is when an advisory &lt;em&gt;entered the record&lt;/em&gt;, not when the vulnerability was introduced or first disclosed — so this measures advisory-publication velocity, not vulnerability incidence. Bulk imports show up as spikes (a log4j-era Java backfill in 2022, a large 2026 ingestion across ecosystems), which is why we lead with complete years through 2025 and use a 2023-2025 average for the "recent flow" figures. Tool counts reflect catalog coverage, not capability — recall/precision of any tool is out of scope, and commercial tools aren't counted. No scanner is named or scored; the tool axis is an aggregate per-language count.&lt;/p&gt;




&lt;p&gt;Full study, the complete table (including Go, 2026 partial-year columns, and the FAQ) and the reproduction script: &lt;a href="https://zennoxa.com/research/advisory-growth-vs-tooling-coverage-2026" rel="noopener noreferrer"&gt;Advisory Growth vs. Tooling Coverage on zennoxa.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>appsec</category>
      <category>devsecops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Rust has 1,332 vulnerability advisories for every open-source scanner. Dart has zero scanners.</title>
      <dc:creator>hamelin123</dc:creator>
      <pubDate>Thu, 20 Aug 2026 03:38:49 +0000</pubDate>
      <link>https://dev.to/hamelin123/rust-has-1332-vulnerability-advisories-for-every-open-source-scanner-dart-has-zero-scanners-1p49</link>
      <guid>https://dev.to/hamelin123/rust-has-1332-vulnerability-advisories-for-every-open-source-scanner-dart-has-zero-scanners-1p49</guid>
      <description>&lt;p&gt;We keep hearing that dependency scanning is a solved problem — pick a tool, wire it into CI, done. That's true if you write JavaScript or Python. If you write Rust, Dart, or Elixir, the map has holes you can measure.&lt;/p&gt;

&lt;p&gt;We counted the vulnerability advisories in each package ecosystem (from OSV.dev) against the number of open-source tools that can actually scan it (from the analysis-tools.dev catalog). The mismatch is not subtle.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Across 11 ecosystems: &lt;strong&gt;47,422 vulnerability advisories&lt;/strong&gt;, and only &lt;strong&gt;42 open-source security tools&lt;/strong&gt; to cover all of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust&lt;/strong&gt; has &lt;strong&gt;1,332 advisories per open-source scanner&lt;/strong&gt; (2,663 advisories, 2 tools). Python's ratio is 999:1, PHP 979:1, Go 715:1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dart (Pub)&lt;/strong&gt; and &lt;strong&gt;Elixir (Hex)&lt;/strong&gt; are "SCA deserts": real advisories exist (13 and 194), and &lt;strong&gt;zero catalogued open-source scanners&lt;/strong&gt; cover them.&lt;/li&gt;
&lt;li&gt;Reproducible from two public datasets. The counting has one honest twist — see npm below.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advisories per open-source scanner
&lt;/h2&gt;

&lt;p&gt;The signal (known vulnerabilities) and the capacity to scan for it (tools) are, in the study's words, "only weakly aligned." Here's the ratio for the busiest ecosystems:&lt;/p&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;Vuln advisories&lt;/th&gt;
&lt;th&gt;OSS tools&lt;/th&gt;
&lt;th&gt;Advisories per tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rust (crates.io)&lt;/td&gt;
&lt;td&gt;2,663&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,332 : 1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python (PyPI)&lt;/td&gt;
&lt;td&gt;12,992&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;999 : 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP (Packagist)&lt;/td&gt;
&lt;td&gt;6,851&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;979 : 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;8,577&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;715 : 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript (npm)&lt;/td&gt;
&lt;td&gt;6,998&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;700 : 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java (Maven)&lt;/td&gt;
&lt;td&gt;6,859&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;686 : 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A high ratio doesn't mean the tools are bad — the good ones scale fine. It means the &lt;em&gt;diversity&lt;/em&gt; of coverage is thin: if the two Rust scanners miss an ecosystem-specific advisory format or a new source, there's no third option to catch it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The deserts: signal with no open-source scanner
&lt;/h2&gt;

&lt;p&gt;Two ecosystems have vulnerability advisories and, per the catalog, &lt;strong&gt;no open-source security scanner at all&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dart (Pub):&lt;/strong&gt; 13 advisories, 0 tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elixir (Hex):&lt;/strong&gt; 194 advisories, 0 tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;194 known-vulnerable-package advisories with zero open-source coverage is not a rounding error for a team shipping Phoenix apps. This is exactly the kind of gap that stays invisible until someone asks "why didn't our scanner catch that?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The npm twist (why raw counts lie)
&lt;/h2&gt;

&lt;p&gt;npm looks terrifying if you take OSV at face value: &lt;strong&gt;223,802 advisories&lt;/strong&gt;. But &lt;strong&gt;96.9% of those are malicious-package advisories&lt;/strong&gt; (the &lt;code&gt;MAL-&lt;/code&gt; prefix — typosquats, protestware, install-script miners), not vulnerabilities in legitimate packages. Lump them together and npm looks like the riskiest ecosystem on earth; split them out and the real vulnerability count is &lt;strong&gt;6,998&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That split matters for honesty. A vendor motivated to make a number look big would quote the 223,802. We separated malicious-package advisories from vulnerability advisories precisely so the per-ecosystem comparison isn't distorted — and so we're not the vendor quoting the scary number.&lt;/p&gt;

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

&lt;p&gt;Two public datasets, no survey:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;OSV.dev&lt;/strong&gt; per-ecosystem archives — the JSON advisory feeds, counted per ecosystem, with &lt;code&gt;MAL-&lt;/code&gt; advisories separated out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;analysis-tools.dev&lt;/strong&gt; catalog — open-source tools tagged &lt;code&gt;security&lt;/code&gt;, counted per language.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# advisories:  OSV.dev per-ecosystem archives (split MAL- from vuln)&lt;/span&gt;
&lt;span class="c1"&gt;# tools:       analysis-tools.dev catalog, security-tagged, per language&lt;/span&gt;
&lt;span class="c1"&gt;# full parser + the 47,422-advisory / 42-tool derivation:&lt;/span&gt;
&lt;span class="s"&gt;zennoxa.com/research/sca-coverage-gap-2026&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete table — all 11 ecosystems, the malicious-vs-vuln split, and the commands to reproduce it — is here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ &lt;a href="https://zennoxa.com/research/sca-coverage-gap-2026" rel="noopener noreferrer"&gt;The SCA coverage gap: where vulnerability signal outruns open-source tooling&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Published by Zennoxa Research. If your ecosystem has an open-source scanner the catalog missed, that changes the ratio — tell us and we'll correct it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>opensource</category>
      <category>rust</category>
      <category>devops</category>
    </item>
    <item>
      <title>The same detector scores 45.5 or 100 on the OWASP Benchmark. Both are 'true.'</title>
      <dc:creator>hamelin123</dc:creator>
      <pubDate>Wed, 19 Aug 2026 09:45:32 +0000</pubDate>
      <link>https://dev.to/hamelin123/the-same-detector-scores-455-or-100-on-the-owasp-benchmark-both-are-true-512k</link>
      <guid>https://dev.to/hamelin123/the-same-detector-scores-455-or-100-on-the-owasp-benchmark-both-are-true-512k</guid>
      <description>&lt;p&gt;Every SAST vendor quotes an accuracy number. Almost none of them tell you the three things you'd need to reproduce it. We took a single, fixed detector and showed that its "accuracy" on the OWASP Benchmark swings by more than 50 points depending on choices that have nothing to do with the detector itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A SAST accuracy score is &lt;strong&gt;not reproducible&lt;/strong&gt; unless three things are disclosed: the &lt;strong&gt;benchmark version&lt;/strong&gt;, the &lt;strong&gt;CWE subset&lt;/strong&gt; that was averaged, and the &lt;strong&gt;matching rule&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Same detector, same detections — score comes out &lt;strong&gt;45.5&lt;/strong&gt; across all 11 categories, or &lt;strong&gt;100.0&lt;/strong&gt; on the injection-only subset. A &lt;strong&gt;54.5-point swing&lt;/strong&gt; from subset selection alone.&lt;/li&gt;
&lt;li&gt;The OWASP Benchmark's official &lt;strong&gt;macro-average weights the smallest category 14.4× more&lt;/strong&gt; than a case-weighted average would. We computed all of this from the suite's own public ground truth; the script is in the study.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why one number hides four decisions
&lt;/h2&gt;

&lt;p&gt;The OWASP Benchmark is the closest thing the SAST world has to a shared ruler. But "score = X" collapses at least four independent choices into one figure, and each one moves the result:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Which version of the benchmark.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Test cases&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;v1.1&lt;/td&gt;
&lt;td&gt;21,041&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v1.2&lt;/td&gt;
&lt;td&gt;2,740&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;v1.2 is &lt;strong&gt;7.7× smaller&lt;/strong&gt; than v1.1. A false-positive rate computed over 21,041 cases and one computed over 2,740 are not the same measurement, and "OWASP Benchmark score" rarely says which population it's over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Macro-average vs. case-weighted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The official scorer takes a &lt;strong&gt;macro-average&lt;/strong&gt; — every category counts equally, regardless of how many test cases it has. That sounds fair until you look at what it does to the small categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;XPath injection&lt;/strong&gt; has 35 test cases. Under the macro-average it gets &lt;strong&gt;9.1%&lt;/strong&gt; of the score (1 of 11 categories). Weighted by its actual case count it would get &lt;strong&gt;1.3%&lt;/strong&gt;. That's a &lt;strong&gt;14.4× inflation&lt;/strong&gt; of the smallest category.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL injection&lt;/strong&gt; has 504 cases — it gets the same &lt;strong&gt;9.1%&lt;/strong&gt; under macro, but &lt;strong&gt;18.4%&lt;/strong&gt; when weighted by cases. So the official average makes SQLi count roughly &lt;em&gt;half&lt;/em&gt; as much as its share of the suite.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither weighting is wrong. But they answer different questions, and a headline number doesn't tell you which one you're looking at.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Which CWE subset got averaged.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's the part that should make you suspicious of any single figure. Take a neutral probe that scores perfect detection on the injection families and nothing else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Averaged across &lt;strong&gt;all 11 categories&lt;/strong&gt;: &lt;strong&gt;45.5&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;On the &lt;strong&gt;injection-only subset&lt;/strong&gt;: &lt;strong&gt;100.0&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same probe. &lt;strong&gt;54.5 points&lt;/strong&gt; of difference, entirely from which categories you chose to report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. How you match a finding to an expected result.&lt;/strong&gt; Line-level, method-level, or file-level matching each produce a different true/false-positive count from identical scan output.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it was computed
&lt;/h2&gt;

&lt;p&gt;Nothing here is an estimate. We ran it against v1.2 ground truth using the OWASP BenchmarkUtils scorer with the &lt;strong&gt;Youden index&lt;/strong&gt; — &lt;code&gt;(sensitivity + specificity) − 1&lt;/code&gt;, normalized to 0–100 — and derived the category counts and weightings straight from the suite's public &lt;code&gt;expectedresults-1.2.csv&lt;/code&gt;. Change one of the four knobs, keep the detector fixed, and watch the headline move.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# reproduce the weighting + subset math from the official file:
OWASP Benchmark  -&amp;gt;  expectedresults-1.2.csv   (2,740 rows)
# our parser + the full 45.5-vs-100 derivation:
zennoxa.com/research/sast-benchmark-version-drift-2026
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What to actually ask for
&lt;/h2&gt;

&lt;p&gt;When a tool (ours included) quotes an OWASP Benchmark score, ask three questions before you believe it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Which version&lt;/strong&gt; — v1.1 or v1.2?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which categories&lt;/strong&gt; were averaged, and macro or case-weighted?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What matching rule&lt;/strong&gt; turned scan output into true/false positives?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A score that can answer all three is a measurement. A score that can't is a billboard.&lt;/p&gt;

&lt;p&gt;The full derivation — every category's weight, the four knobs, and the reproducible script — is here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ &lt;a href="https://zennoxa.com/research/sast-benchmark-version-drift-2026" rel="noopener noreferrer"&gt;Is a published SAST 'accuracy' score even reproducible?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Published by Zennoxa Research. We hold our own numbers to this bar — if a claim on our site can't answer the three questions, it's a bug; tell us.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>sast</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>There are 755 static-analysis tools. Only 42 are open-source security scanners.</title>
      <dc:creator>hamelin123</dc:creator>
      <pubDate>Wed, 19 Aug 2026 08:02:37 +0000</pubDate>
      <link>https://dev.to/hamelin123/there-are-755-static-analysis-tools-only-42-are-open-source-security-scanners-3256</link>
      <guid>https://dev.to/hamelin123/there-are-755-static-analysis-tools-only-42-are-open-source-security-scanners-3256</guid>
      <description>&lt;p&gt;If you run a linter on your code today, you have a lot of choices. If you want one that actually looks for &lt;em&gt;security&lt;/em&gt; bugs — and is open source — you have far fewer than the ecosystem's size suggests.&lt;/p&gt;

&lt;p&gt;We parsed the public &lt;a href="https://github.com/analysis-tools-dev/static-analysis" rel="noopener noreferrer"&gt;analysis-tools.dev&lt;/a&gt; catalog (MIT-licensed, 755 tools) to get an actual count instead of a vibe. Here's what fell out.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Of &lt;strong&gt;755&lt;/strong&gt; static-analysis tools in the catalog, &lt;strong&gt;86%&lt;/strong&gt; are open source — but only &lt;strong&gt;42&lt;/strong&gt; are open-source tools whose job is finding &lt;em&gt;security&lt;/em&gt; bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;21 languages&lt;/strong&gt; that already have an active linting ecosystem (five or more general static-analysis tools each) have &lt;strong&gt;zero&lt;/strong&gt; open-source security scanner. SQL, Shell, PowerShell, Dart, Elixir, Lua, R, Groovy, Clojure and Haskell are on that list.&lt;/li&gt;
&lt;li&gt;Every number here is reproducible from one public dataset. No survey, no vendor list, no "leaders" quadrant.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why the gap is easy to miss
&lt;/h2&gt;

&lt;p&gt;"Static analysis" and "security scanner" get used interchangeably, and the catalog is full of tools — so it &lt;em&gt;feels&lt;/em&gt; like the security-scanner space is crowded. When you split the catalog by what each tool is actually for, the picture changes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Slice&lt;/th&gt;
&lt;th&gt;Count&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;All static-analysis tools&lt;/td&gt;
&lt;td&gt;755&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open source (any purpose)&lt;/td&gt;
&lt;td&gt;653&lt;/td&gt;
&lt;td&gt;86.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security-focused (SAST)&lt;/td&gt;
&lt;td&gt;69&lt;/td&gt;
&lt;td&gt;9.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open-source &lt;em&gt;and&lt;/em&gt; security-focused&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;42&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;61% of the security tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A general linter tells you a function is too long. A security scanner tells you that a value from &lt;code&gt;request.args&lt;/code&gt; reached a SQL string without going through a parameterizer. Both are "static analysis." Only one is looking for the bug that ends up in a CVE. The catalog has 653 of the first kind and 42 of the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 21-language hole
&lt;/h2&gt;

&lt;p&gt;The more interesting finding isn't the total — it's &lt;em&gt;where the 42 aren't&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We took every language that has at least five general static-analysis tools (i.e. a language with a real tooling community, not a niche one) and checked how many have an open-source security scanner. Twenty-one of them have none:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SQL, Shell, Groovy, R, Lua, Dart, PowerShell, Elixir, Clojure, Haskell — and eleven more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some of those are load-bearing. Shell and PowerShell run your CI and your production boxes. SQL is where injection lives. Dart ships to phones. If you write those and want an open-source tool that reasons about security specifically, the catalog says you're on your own.&lt;/p&gt;

&lt;p&gt;Where the 42 &lt;em&gt;do&lt;/em&gt; cluster is unsurprising: Python (13 scanners), Go (12), Java (10), JavaScript (9). The languages with the most security tooling are the ones that already had the most tooling.&lt;/p&gt;

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

&lt;p&gt;Nothing here needs to be taken on faith. The method is three steps against one file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt; — split proprietary vs. open source using the catalog's license field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security scope&lt;/strong&gt; — keep only tools tagged &lt;code&gt;security&lt;/code&gt; in the catalog taxonomy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language coverage&lt;/strong&gt; — read each tool's language tags and count per language.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The catalog is a single JSON file in a public MIT repo. We publish the parser and the raw counts alongside the study, so you can re-run it and get the same 42 — or disagree with a classification and see exactly which tool moved the number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# the dataset:
github.com/analysis-tools-dev/static-analysis  (data/*.yml)
# our parser + raw counts:
zennoxa.com/research/state-of-oss-sast-2026  -&amp;gt;  data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why we bothered
&lt;/h2&gt;

&lt;p&gt;We build a security scanner (&lt;a href="https://zennoxa.com" rel="noopener noreferrer"&gt;Shield&lt;/a&gt;), so the honest disclosure is that this map has a self-interested corner. But the count doesn't change based on who's counting — 42 is 42, and the 21-language hole is in the public data whether or not you've heard of us. We'd rather publish the census than a quadrant.&lt;/p&gt;

&lt;p&gt;The full breakdown — every language, the license splits, and the reproducible &lt;code&gt;data.json&lt;/code&gt; — is here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ &lt;a href="https://zennoxa.com/research/state-of-oss-sast-2026" rel="noopener noreferrer"&gt;State of Open-Source SAST 2026&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Published by Zennoxa Research. If you think a tool is misclassified, the raw counts are right there — tell us which one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>sast</category>
      <category>opensource</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
