Safeguard
Developer Tools•

Does a high test coverage percentage mean your code is secure?

Line coverage shows which code ran in tests, not whether it was checked for abuse. Learn what coverage can and cannot say about security, and what to add.

Safeguard Security Team
3 min read

No. Test coverage reports which lines executed while tests ran. It does not show whether the tests checked for hostile input, broken authorisation or unsafe defaults. High coverage can sit beside serious flaws. Use coverage as a floor for risky modules and add tests that assert security behaviour.

What coverage counts

Coverage tools mark each line, branch or function as executed or not. A line that ran inside a test counts as covered even if the test never looked at its result. A test that calls a login handler with valid credentials and checks nothing else will cover that handler.

So coverage answers "was this code exercised?" and not "was this code verified against abuse?"

The gap between executed and checked

Think of three layers of confidence:

  1. The line ran.
  2. The line produced the expected result for normal input.
  3. The line behaves safely for hostile input.

Coverage measures the first. Most unit tests reach the second. Security failures live in the third: an ID that belongs to another user, a path with parent directory segments, an oversized payload, a missing authentication check on one route.

Why a target on the percentage backfires

If a team must hit a number, the quickest route is tests that call code and assert little. This is Goodhart's law again: when a measure becomes a target it stops being a good measure. The result is a high figure and a false sense of safety.

It also directs effort to easy code. Getters and plain data classes are cheap to cover. Authorisation checks, parsers and serialisers are harder and matter more.

Where coverage is useful for security

Use it narrowly:

  • As a floor on sensitive modules. Authentication, access control, input parsing and cryptographic wrappers should not be untested.
  • As a diff check. Flag pull requests that add security relevant code with no tests at all.
  • As a hint, not a verdict. A module with very low coverage and a history of defects deserves review.

Tests that add security value

Test typeWhat it asserts
Negative authorisationUser A cannot read or change user B's record
Boundary inputEmpty, huge, malformed and unexpected types are rejected
Default safetyNew endpoints require authentication unless explicitly public
RegressionA past vulnerability stays fixed

A short list of these for each service tells you more than a coverage figure does.

Steps to improve the signal

  1. List the five riskiest code paths per service: login, permissions, uploads, parsers, payments.
  2. Write at least one negative test for each.
  3. Add a rule that any fixed vulnerability ships with a regression test.
  4. Track the count of negative tests on those paths rather than the overall percentage.
  5. Complement tests with static and dependency analysis, since tests rarely cover third party code.

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 100 percent coverage a security guarantee?

No. It means every line ran during tests, not that any test checked for abuse.

What should we measure instead?

Count negative and regression tests on the riskiest paths, and keep coverage as a floor for sensitive modules.

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.