Skip to content

Vulnerability management metrics that matter

Define and compute the metrics a VOC needs: time to remediate with percentiles, SLA compliance, coverage, backlog age, KEV exposure windows and reopen rate.

Published on 6 min read

What a vulnerability program measures shapes what people do. Measure raw finding counts and teams will argue about scanner accuracy and close easy items first. Measure closed tickets and tickets will close without anything being fixed. Measure the right things — how fast risk is removed, how complete your visibility is, how long the organization stays exposed to vulnerabilities attackers actually use — and behaviour aligns with the goal.

This guide defines the metrics a Vulnerability Operations Center needs, shows how to compute the important ones with SQL against a simple findings table, and highlights the ways each can mislead. The companion guide, reporting vulnerability risk to leadership, covers how to present them.

Principles

  • Prefer flow to stock. How fast findings move through the lifecycle says more than how many are sitting in it.
  • Segment by tier. An average across P1 and P4 findings means nothing. Every metric should be reportable per priority tier, and usually per owning team and asset class.
  • Include what's still open. Metrics computed only on closed findings are survivorship-biased: the hardest, oldest items are exactly the ones missing.
  • Normalize by coverage. A count only makes sense next to how much of the estate you can see.
  • Trend, don't snapshot. One month's number is noise; six months of the same definition is information.

The metric catalogue

MetricDefinitionWhy it mattersMain pitfall
Time to remediate (TTR)Resolved date minus first detected date, per finding; reported as median, 90th percentile and meanCore measure of how fast risk is removedIgnores still-open findings; mean skewed by outliers
SLA complianceFindings closed on or before due date ÷ findings closed in the period, plus open past-due countWhether commitments are metClosed-only version hides overdue backlog
Open past dueOpen findings beyond their due date, by tier and age beyond dueThe actual current SLA debtNeeds reliable due dates
Assessment coverageIn-scope assets with a successful assessment within policy ÷ in-scope assetsVisibilityDepends on inventory completeness
Authenticated coverageAs above, counting only authenticated scans or agent resultsQuality of visibilitySilent credential failures
Backlog ageDistribution of age of open findings, by tierLong-tail riskAverages hide the tail
KEV exposure windowFor KEV-listed findings: time from KEV addition (or detection, if later) to resolutionExposure to vulnerabilities known to be exploitedNeeds KEV date history
Detection lagFirst detected date minus CVE publication dateSpeed of discoveryPublication dates can be misleading for old CVEs
Reopen rateResolved findings later detected again ÷ resolved findingsQuality of fixes and of build pipelinesNeeds stable finding keys
Exception loadActive exceptions by tier; share of open P1/P2 risk under exceptionHidden, accepted riskBlanket exceptions distort it

MTTR is the metric most programs start with. It is useful, but it should never be reported alone.

Why percentiles beat the mean

Time-to-remediate distributions are heavily skewed: most findings close within a normal patch cycle, and a small number stay open for months. The mean is sensitive to that tail, so it can move a lot because of a handful of legacy items, and it hides whether the typical experience is improving. The median shows the typical finding; the 90th percentile shows how bad the slow end is. Reporting both, per tier, gives a far more honest picture.

There is a subtler problem: TTR computed on closed findings ignores everything still open. If a team fixes all its easy findings quickly and leaves the hard ones, its TTR looks excellent. Two remedies:

  1. Always report open backlog age next to TTR.
  2. For mature programs, borrow from survival analysis: estimate the probability that a finding is still open after N days, treating open findings as censored observations. A Kaplan–Meier curve per tier answers "what share of P1 findings are fixed within 7, 14, 30 days?" without ignoring the open ones.

A minimal data model

The SQL below assumes a findings table produced by your remediation workflow:

CREATE TABLE findings (
  finding_key     text PRIMARY KEY,   -- asset + vulnerability + component
  asset_id        text NOT NULL,
  owner_team      text,
  tier            text NOT NULL,      -- P1..P4 at time of measurement
  cve             text,
  in_kev          boolean DEFAULT false,
  kev_added       date,
  first_detected  timestamptz NOT NULL,
  due_at          timestamptz NOT NULL,
  resolved_at     timestamptz,        -- set only on verified evidence
  status          text NOT NULL       -- open | resolved | risk_accepted | false_positive
);

Median and 90th percentile time to remediate, per tier

SELECT tier,
       count(*)                                                    AS resolved,
       percentile_cont(0.5) WITHIN GROUP (ORDER BY
         extract(epoch FROM resolved_at - first_detected) / 86400) AS median_days,
       percentile_cont(0.9) WITHIN GROUP (ORDER BY
         extract(epoch FROM resolved_at - first_detected) / 86400) AS p90_days,
       avg(extract(epoch FROM resolved_at - first_detected) / 86400) AS mean_days
FROM   findings
WHERE  status = 'resolved'
  AND  resolved_at >= date_trunc('quarter', now())
GROUP  BY tier
ORDER  BY tier;

SLA compliance, including the open backlog

WITH closed AS (
  SELECT tier,
         count(*) FILTER (WHERE resolved_at <= due_at) AS on_time,
         count(*)                                       AS total
  FROM   findings
  WHERE  status = 'resolved'
    AND  resolved_at >= now() - interval '90 days'
  GROUP  BY tier
), overdue AS (
  SELECT tier, count(*) AS open_past_due
  FROM   findings
  WHERE  status = 'open' AND due_at < now()
  GROUP  BY tier
)
SELECT c.tier,
       round(100.0 * c.on_time / nullif(c.total, 0), 1) AS pct_closed_on_time,
       coalesce(o.open_past_due, 0)                      AS open_past_due
FROM   closed c
LEFT   JOIN overdue o USING (tier)
ORDER  BY c.tier;

KEV exposure window

SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY extract(epoch FROM
         coalesce(resolved_at, now()) - greatest(first_detected, kev_added::timestamptz)) / 86400)
         AS median_kev_exposure_days,
       count(*) FILTER (WHERE status = 'open') AS kev_findings_still_open
FROM   findings
WHERE  in_kev;

Using coalesce(resolved_at, now()) deliberately includes open items at their current age, so the metric cannot improve by leaving KEV findings unresolved.

Coverage metrics

Coverage comes from the asset inventory, not the scanner. Break it down by asset class and business unit, and report authenticated coverage separately from any-coverage. When coverage improves, expect open finding counts to rise; annotate reports so nobody mistakes better visibility for worse security.

Goodhart's law in practice

"When a measure becomes a target, it ceases to be a good measure." Every metric above can be gamed, and knowing how is the best defence:

  • TTR improves if hard findings are excepted instead of fixed → report exception load next to it.
  • SLA compliance improves if tiers are downgraded → audit tier changes and restrict who can make them.
  • Open counts fall if scanners lose access → always pair with coverage.
  • Closure rates rise if findings are resolved by ticket state rather than evidence → only verified resolution counts.
  • Reopen rate falls if new findings are created instead of reopening old ones → enforce stable finding keys.

A small set of paired metrics — speed with quality, remediation with exceptions, counts with coverage — is much harder to game than any single number.

A starter dashboard

For the team (weekly): open P1/P2 by owner with due dates; findings due in the next 7 days; new KEV additions affecting you; authentication failures by scan scope.

For management (monthly): median and 90th percentile TTR per tier; SLA compliance per tier and team; open past due; KEV exposure window; authenticated coverage; active exceptions.

For executives (quarterly): trends of the management set, plus narrative — see reporting to leadership.

Related guides

07 · Metrics & Reporting
How a VOC reports to executives and the board: audiences, a one-page structure, KRIs vs KPIs, trends over snapshots, and what to leave out.
05 · Remediation Workflow
Design risk-based vulnerability remediation SLAs: tiers instead of raw CVSS, when the clock starts and pauses, escalation, and measuring compliance.
03 · Scanning Strategy
Design a scanning strategy for a VOC: authenticated scans, agents, cloud and container assessment, SCA, DAST, safe scanning and measurable coverage.