DEV Community

Cover image for I scanned 8 popular open-source repos for outdated dependencies and CVEs. Here's what I found.
Jorge Cedillo
Jorge Cedillo

Posted on • Originally published at trustdev.hashnode.dev

I scanned 8 popular open-source repos for outdated dependencies and CVEs. Here's what I found.

Most developers know their dependencies are probably outdated. Few know by how much.

I built ScanReq, a VS Code extension that scans dependency files, checks versions against public registries in real time, and queries OSV.dev for known CVEs. It supports 8 ecosystems: Python, Node.js, Rust, Go, PHP, Ruby, and Java (both Maven and Gradle).

To stress-test it, I pointed it at repos that most developers have heard of. Not toy projects — real, actively maintained codebases with real users.

Here's what came out.


The results

Repo Ecosystem Outdated CVEs Notable
rails/rails Ruby 89 7 (5 HIGH) 5 HIGH-severity CVEs in rack alone
cli/cli Go 49 1 177 modules parsed from go.mod
veloren/veloren Rust 28 4 Cargo.lock resolved from workspace root
spring-petclinic Java (Maven) 5 HIGH Some CVEs have no patch available
spring-petclinic Java (Gradle) 3 HIGH Same project, different build tool, different results
apt-mirror2 Python 14 0 pip-compile format with hashes
laravel/laravel PHP 6 0 phpunit sitting on a major version behind
libphonenumber-js Node.js 20 1 HIGH CVE in rollup, a dev dependency

A few things stood out.


"Outdated" doesn't mean "broken"

rails/rails shows 89 outdated packages. That sounds alarming until you realize many of those are intentionally pinned by the Rails core team. They know what they're doing.

The real value isn't in the number — it's in knowing which ones are outdated and why it matters. A minor patch bump on a logging library is not the same as a HIGH-severity CVE on rack, which handles every HTTP request your Rails app processes.

This is where the raw count is misleading and why I spent time making the results panel show context: severity, version gap, whether a fix exists, and whether it's a major version jump that might include breaking changes.

Frameworks vs. real projects

This is something I learned the hard way while testing. The tool works best on real-world projects — apps, services, CLIs — where dependencies accumulate organically over months or years. Nobody audits their package.json after every sprint.

Frameworks and starter templates (like laravel/laravel or spring-petclinic) are useful for testing, but they don't reflect reality. They have few dependencies, tightly pinned, maintained by core teams who watch every version bump. The interesting results come from repos where a team shipped features for a year without running a dependency audit.

If you want to see what ScanReq actually does for you, try it on your project, not on a template.

The manual verification test

I wanted to make sure the results weren't just noise, so I did something tedious: I manually verified every single result on veloren/veloren — a Rust game with roughly 60 dependencies.

For each package, I went to crates.io, checked the latest published version, and compared it with what ScanReq reported. Then for each CVE, I went to osv.dev, looked up the advisory, and confirmed the severity and affected version ranges matched.

It took me roughly 4 hours.

ScanReq does the same thing in about 8 seconds.

If you don't trust automated tools (and you shouldn't, blindly), pick any CVE ID from a ScanReq scan and paste it into osv.dev. The data is all public. That's the whole point — the tool doesn't have a proprietary database. It queries the same public sources you would, just faster.


Things that were harder than expected

Building a version checker sounds simple until you actually try to parse real-world dependency files. A few things that surprised me:

Cargo.lock isn't always next to Cargo.toml. In Rust workspaces, the lockfile lives at the workspace root, which can be 3, 4, or 5 directories above the crate you're looking at. ScanReq walks up the directory tree to find it. Same story with composer.lock in PHP monorepos.

pip-compile output is hostile. It adds trailing backslashes for line continuation and SHA256 hashes after every version. A naive regex that looks for ==1.2.3 will grab ==1.2.3 \ instead. I had to handle this specifically.

Ruby Gemfiles can include other Gemfiles. The eval_gemfile directive loads another file recursively. And platform-specific gems (:windows, :jruby, %i[mswin mingw]) need to be filtered out on non-matching platforms, not flagged as unverified.

Maven BOMs are a version indirection layer. Spring Boot projects declare dependencies without versions — those come from a BOM (Bill of Materials) defined elsewhere. You have to download and parse the BOM's <properties> block before you can even tell if a package is outdated.

None of this is rocket science, but it's the kind of thing you only discover by testing against real repos, not by reading the spec.


How it works, briefly

  1. You open a project in VS Code with a supported dependency file (requirements.txt, package.json, Cargo.toml, go.mod, composer.json, Gemfile, pom.xml, or build.gradle).
  2. Run ScanReq: Scan dependencies from the Command Palette.
  3. ScanReq parses the file, queries the public registry for each package (PyPI, npm, crates.io, proxy.golang.org, Packagist, RubyGems, or Maven Central), and checks OSV.dev for known CVEs.
  4. Results show in a visual panel inside VS Code: outdated packages, version gaps, CVE details with severity and GHSA links, and smart insights.

Everything happens locally — the queries go directly from your machine to the public registries. Nothing passes through my servers (except license validation if you're on Pro).


Free vs. Pro

The free tier covers all 8 ecosystems, version checking, and CVE detection for exact versions. That's the core of the tool and it's not going away.

Pro ($19, one-time payment, no subscription) adds:

  • CVE detection for non-exact versions — if your requirements.txt says >=1.2 instead of ==1.2.3, Pro resolves the installed version and checks it
  • Cross-version compatibility analysis — flags conflicts before they break your build
  • 3-phase update plan — groups updates by risk level (safe patches → minor bumps → major/breaking) so you don't update everything at once and wonder what broke
  • AI prompt export — one click to copy a structured prompt with your scan results for Claude, Copilot, or Cursor

I went with a one-time payment because I personally hate SaaS subscriptions for developer tools. You pay once, you own it. No tracking, no analytics, no "upgrade to keep your features."


Try it

Install from the VS Code Marketplace:

ext install trustdev.scanreq
Enter fullscreen mode Exit fullscreen mode

Or visit scanreq.com to see screenshots and demo videos of real scans.

Source code: github.com/JorgeCedilloAbarca/scanreq

If you run it on your project and find something interesting, I'd genuinely like to hear about it. The best bug reports I've gotten have come from repos with dependency setups I never anticipated.

Top comments (0)