Finding things
Dependency vulnerabilities
A real SBOM first, then vulnerabilities against it, then the exploitation data that makes the ranking mean something.
SBOM first
syft builds a bill of materials from what is actually in the checkout rather than from what a manifest claims. grype and osv-scanner then run against that, which is why a lock file that disagrees with the manifest does not hide anything.
The half a manifest does not name
A pom names three libraries and resolves to forty, and it is the other thirty seven that are usually old and usually exploitable. Reading them means resolving the tree, which is Maven's job rather than an SBOM tool's, and running the build to find out means executing whatever the repository says to execute inside the scanner. So it asks the host, which has already resolved the tree, runs nothing and costs one request. That works where the host publishes such a graph, which today means GitHub. Measured on two packages that appear in no manifest anywhere: eleven vulnerabilities, including Log4Shell on log4j-core 2.6.2.
.NET that was never built
syft ships three .NET catalogers and not one of them reads a source project: one wants a deps.json, one wants a packages.lock.json, one wants a compiled assembly. What a source repository actually holds is a csproj listing PackageReference entries, or on an older project a packages.config, so a .NET repository that has not been built looked like a repository with no dependencies. Those files are read directly now and their packages go into the SBOM, where the vulnerability matcher already looks. A version that is a range, or an MSBuild property nobody expanded, is skipped rather than guessed at: a wrong version produces a confident wrong answer about whether something is vulnerable.
Ranking that survives contact
Every finding carries whether it is on the CISA list of vulnerabilities being exploited in the wild, and its EPSS score, which is the published probability of exploitation in the next thirty days. A medium on the exploited list matters more than a critical nobody has ever used.
Container images too
The base image each Dockerfile names is resolved and read from its registry with nothing built. On most applications the operating system layer is where the critical count actually lives.
What it does not do
The vulnerability data is public: OSV, the GitHub advisory database and the NVD. Commercial products curate their own and are often earlier. That is a real difference and it is the main thing you buy with a license. A resolved tree comes from the host, so on the eleven providers that do not publish one a Java or .NET project is read as the libraries its manifests declare rather than the tree they install. A transitive dependency pulled in by a .NET project file is not seen even on GitHub, because there what is declared is what is read.
Every feature page carries one of those. The comparison page scores the same ground against five products people pay for, including the rows that go against us.