Safeguard
Industry Analysis•

Are vulnerabilities per thousand lines of code a fair comparison?

Normalising findings by size sounds fair but has traps. See when per-line, per-service or per-dependency rates help a team and when they mislead readers.

Safeguard Security Team
3 min read

Only partly. Dividing findings by code size removes one obvious bias, but lines of code vary by language, style and generated files, and findings depend on scanner and rules. A rate is fair for tracking one codebase over time with fixed tooling. It is a poor way to rank teams or products.

Why normalise at all

Raw counts punish large systems. A service with ten times the code will usually have more findings, and a leaderboard of raw counts mostly lists the biggest teams. Dividing by a size measure is meant to level that.

The intent is right. The usual denominators have problems.

Common denominators and their traps

DenominatorGood forTrap
Lines of codeTrend within one repoLanguage and style change line counts; generated code inflates it
Number of reposOrg level summaryA repo can be a tiny script or a monolith
Number of dependenciesSupply chain exposureCounting method differs between tools
Number of developersCapacity viewPenalises small teams with big surface
Number of deploymentsRelease safety viewRewards shipping tiny changes
Number of servicesPortfolio viewServices are not equal in size or exposure

No single column is neutral. Each one encodes an opinion about what "the same size" means.

The numerator has a bias too

A rate divides one noisy thing by another. Findings depend on which scanner ran, which rule set, whether transitive dependencies were read and how duplicates were merged. Two teams with identical code can score differently because one tool is stricter. If the numerator definition changes mid year, the trend line breaks, whatever the denominator.

When a rate is reasonable

  • Comparing one repository against itself, same tool, same configuration, quarter to quarter.
  • Spotting an outlier inside a similar group, as a prompt to look and not as a verdict.
  • Tracking a rate of a specific class, such as reachable findings per service, where the class is narrow and defined.

Steps to use normalised measures carefully

  1. Fix the numerator definition: tool, rules, severity rule, duplicate handling.
  2. Choose a denominator that matches the question: size for code quality, dependencies for supply chain, services for portfolio.
  3. Exclude generated, vendored and test fixture files from code counts.
  4. Show the raw count and the denominator beside the rate, so readers can check it.
  5. Never use the rate for individual performance reviews.
  6. Re-baseline and annotate whenever the tooling changes.

A word on rankings

Ranking teams by a normalised rate still invites the behaviours that make measures fail. The Campbell's law formulation says the more a quantitative indicator is used for decisions, the more it is subject to corruption pressures and the more it distorts the processes it monitors. A ranking is exactly that kind of use.

Safeguard offers SBOM and dependency scanning, reachability analysis and policy gates. You can run a free scan at gold.safeguard.sh/scan.

Quick check

Is a lower rate always a better codebase?

No. A lower rate can come from a weaker scanner, a bigger denominator or excluded code.

What is the safest way to use a rate?

Track one codebase against itself with fixed tooling, and show raw numbers beside it.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.