# how to measure your mean time to patch

## TL;DR

Mean time to patch is the average time from first detection of a vulnerability to the fix running in production. Define both timestamps precisely, pull them from your scanner and deploy records, and report the mean by severity band. The metric is only as honest as your timestamps, so define them before you compute anything.

```text
how to measure your mean time to patch
```

## Use this when

- Leadership asks how fast the team patches vulnerabilities
- You need to track whether patch performance is improving quarter over quarter
- You are setting or validating patch SLAs by severity
- A compliance framework asks for remediation timeline evidence

## Not for this skill when

- You are measuring incident response or detection speed (different clock, different skill)
- You have no reliable detection or deploy timestamps (fix the records first)
- You want a single number with no breakdown (the breakdown is where the insight lives)

## Steps

### 1. Define the two timestamps

Detection time is when you first knew: the scanner alert timestamp, the advisory publication date, or the ticket creation time, whichever came first. Patch time is when the fix is running in production, not when the PR merged.

Expected: a written definition of both timestamps, agreed once and reused. "PR merged" as patch time flatters the metric by ignoring deploy lag; use production deploy time.

### 2. Collect the records per vulnerability

For each remediated CVE, record the ID, severity, detection timestamp, production patch timestamp, and the service. Scanner exports and deploy logs are the sources; tickets fill the gaps.

Expected: a table with one row per CVE and no missing timestamps. Rows with missing records get excluded and counted separately, not silently dropped.

### 3. Compute the mean by severity band

Average the detection-to-patch duration within critical, high, medium, and low bands. Also compute the median; a few ancient stragglers skew the mean hard.

```bash
python3 -c "import json,statistics; rows=json.load(open('patch-times.json')); [print(s, round(statistics.mean([r['hours'] for r in rows if r['sev']==s]),1)) for s in ['critical','high','medium','low']]"
```

Expected: four numbers plus medians. If critical MTTP is worse than high, your triage routing has a problem worth investigating.

### 4. Track the trend, not just the snapshot

Plot MTTP per quarter. A single quarter's number is trivia; the direction over four quarters is the story.

Expected: a trend line you can show in a review. Improving trend with honest definitions beats a flattering number with fuzzy ones.

### 5. Report with the caveats attached

State what counts as detection, what counts as patched, what was excluded, and the sample size. Small samples and excluded rows change the meaning.

Expected: a one-page summary a skeptic can audit. Metrics without methodology are just marketing.

### Variant: MTTP per team or service

Slice the same records by owner. It shows where the process works and where patches stall, which is usually a deploy-pipeline problem rather than a people problem.

### Variant: SLA compliance instead of the mean

Define the SLA per severity (for example, critical in 7 days), then report the percentage patched within SLA. Compliance percentage is often more actionable than the mean.

## Why this happens

Without a measured baseline, patch speed is governed by whoever shouts loudest about the latest CVE. MTTP turns "we patch fast" into a number with a definition, which is what makes SLAs enforceable and improvements visible.

## Edge cases and pitfalls

- Detection timestamp ambiguity: scanner first-seen versus advisory date can differ by weeks; pick one and stay consistent.
- Patches deployed but not enabled: feature-flagged fixes are not patched until the flag is on in production.
- Reopened CVEs: count the full span or track reopen rate separately, but do not quietly reset the clock.
- Dev-only dependencies: exclude them from the main metric or track them separately; they distort the picture.
- Tiny samples: a quarterly MTTP from three CVEs is noise; say so.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_UuAF59WvEjbqzidiukGcQA
