High line coverage does not mean secure code. Coverage says a line ran during a test, not that the test checked anything about it. Use the number to find untested code, and measure security with assertions, negative cases and findings fixed instead.
Myth 1: 90 percent coverage means 90 percent safe
Fact: coverage counts executed lines. A test can run a function and assert nothing. Delete the authorization check and the line count barely moves, while the risk jumps.
Myth 2: coverage targets drive quality
Fact: a target pushes people toward easy tests. Getters and trivial branches get covered, while the hard parts, such as error paths and permission failures, stay untested. If a team is measured on the number, the number will rise whether or not security improves.
Myth 3: 100 percent branch coverage proves no bugs
Fact: coverage cannot see inputs you did not try. A branch can run once with a friendly value and fail with a hostile one. This is where property tests and fuzzing add value, since they vary the inputs and not just the paths.
Myth 4: low coverage areas are the dangerous ones
Fact: sometimes. A better rule is to cross coverage with risk. Code that handles authentication, parsing of untrusted input, deserialization, payments and file paths deserves a much higher bar than an internal report formatter. Look at uncovered lines inside those modules first.
Myth 5: coverage from end to end tests counts the same as unit coverage
Fact: it depends on what is asserted. A broad browser test may touch many lines without checking any security property. Count coverage where the test makes a claim.
What to measure instead
- Security assertions per risky module: denied cases, rejected inputs, tamper checks.
- Mutation score on the critical modules, which asks whether a test fails when the code is changed. See /resources/blog/mutation-testing-to-check-ai-written-tests.
- Fuzz target coverage for parsers, reported by the fuzzing tool.
- The share of fixed vulnerabilities that have a regression test.
- Time from finding to fix.
A worked example
Take a login handler with a lockout rule. A single happy path test gives you high line coverage of the handler. Yet the lockout branch, the disabled account branch and the expired password branch are all unexecuted, and each is a security rule. Reading the uncovered lines in that file tells you exactly which negative tests to write. That is the right use of the number: a map of what is untested, read with risk in mind.
A practical way to use the number
Set a floor so coverage does not slide, review the uncovered lines in risky modules at each release, and never reward a team for the percentage alone. Treat a sudden drop as a prompt to look, not as proof of a problem.
Quick check
Is there a good coverage target for security code?
There is no universal number. Choose a higher floor for authentication and input handling, require negative tests there, and watch the trend rather than a single threshold.
Last reviewed: 19 October 2026.