How the remediation cost is calculated

The method, the constants and the assumptions behind every dollar figure on these dashboards — and the things the figures do not include.

15,236
vulns in 223 projects (13,826 with a CVE ID)
11,652
priced from a public fix (76%)
34,476
engineer-days, priced records
$43,095,388
at $1,250 per engineer-day

What the number means

Each priced vulnerability carries an estimate of the engineering time needed to write and validate its fix, based on the fix the project actually published. The estimate comes from a rubric with three dimensions, each scored 1 to 5. Their sum maps to engineer-days on a fixed curve, and days convert to dollars at a fixed daily rate. The same rubric is applied to every project.

Included: understanding the vulnerability well enough to fix it, writing the change, and proving it works. Not included: finding the vulnerability, triage and coordination, CVE assignment and disclosure, release engineering, and the work downstream users do to deploy the patch. The figures describe the fix, not the whole incident.

The formula

D1 · 1–5
Implementation
lines and files the engineer wrote
+
D2 · 1–5
Reasoning
set by vulnerability class
+
D3 · 1–5
Validation
set by vulnerability class
=
Combined · 3–15
Engineer-days
fixed curve, × $1,250/day

D1 is measured from the fix itself. D2 and D3 come from what kind of vulnerability it is. Severity is not an input — see Severity and CVSS.

D1 — Implementation effort

How big and how spread out the change is: the lines added plus lines deleted, and the number of files, counting only code an engineer wrote (tests, documentation and generated files are excluded — see What counts as written code). The lines set the score: the first row whose line limit the fix fits within. The file count can raise it by one row at most, when the files exceed that row's file limit. When 90% or more of the lines are deletions — a fix that removes a feature — the lines column reads the added lines only; the reasoning and validation scores stay.

D1LinesFiles
1≤ 10 lines≤ 1 file
2≤ 50 lines≤ 2 files
3≤ 200 lines≤ 5 files
4≤ 500 lines≤ 10 files
5more than 500 linesmore than 10 files

So a 74-line change spread over 15 files is D1 4 (lines row 3, raised one row by its files), not D1 5, and one line changed in three files is D1 2. A fix that only upgrades a dependency is set to D1 1 (see below). These rules are grading G7, used since 2026-10-11; before it the larger of the two rows set D1.

D2 & D3 — Reasoning and validation difficulty

D2 — reasoning: how hard it is to find the root cause and decide on the right fix. D3 — validation: how hard it is to confirm the fix works and breaks nothing else. Both are set by the vulnerability class. A use-after-free takes more reasoning than an open redirect, and a request-smuggling fix is harder to test than it is to reason about.

LevelD2D3Vulnerability classesPriced records
Specialist55JIT compiler bugs (incl. miscompilation)33
Expert44Sandbox escape, Race condition, Unsafe deserialization, Type confusion369
Expert43Use-after-free, Memory corruption, Buffer overflow548
Skilled34HTTP request smuggling100
Skilled33Mitigation bypass, Privilege escalation, Undefined behavior, Invalid pointer, Authentication / authorization bypass, Improper access control, Same-origin policy bypass, Server-side request forgery (SSRF), Command injection, SQL injection, XML injection5,429
Standard22Missing boundary check, Integer overflow, Uninitialized memory, Information disclosure, Path traversal, Cross-site scripting (XSS), Cross-site request forgery (CSRF), Open redirect3,147
Routine11Denial of service, Spoofing1,477
Default22Any class not listed above, including other549

When a class name contains more than one listed term, the first term in the rubric's own list wins, and JIT comes first — so a record classed “JIT use-after-free” scores as JIT. 15 projects (Apache Cassandra, Apache Tomcat, Dify, Flowise, Frappe, GitLab, Grafana, Keycloak, Mattermost, Moodle, Nextcloud, OpenMRS, PostgreSQL, Redis, Strapi) define a few component adjustments of ±1 — for example, Tomcat's HTTP/2 and TLS code is one step harder on both dimensions, its Manager app one step easier. Scores always stay within 1–5. 328 of 11,652 priced records (3%) carry a D2 or D3 different from their class default, through these adjustments or project-level calibration.

Combined score → engineer-days → dollars

The combined score (3–15) maps to engineer-days on a curve that gets steeper toward the top: moving from 8 to 9 adds 2 days, moving from 14 to 15 adds 15. Hard fixes are disproportionately expensive, and the curve says so. The four difficulty buckets used in the charts are ranges of the combined score.

CombinedEngineer-daysHoursCostBucketPriced records
30.54$625Low302
40.76$875Low484
518$1,250Low1,410
61.512$1,875Low1,383
7216$2,500Low2,156
8324$3,750Medium2,206
9540$6,250Medium2,029
10756$8,750High904
111080$12,500High634
1215120$18,750Extra High91
1320160$25,000Extra High49
1430240$37,500Extra High2
1545360$56,250Extra High2

These are the published tables. The Effort Model page lets you change the D1 bands, the class table behind D2 and D3, the component adjustments and this curve, and see every figure recalculated. Those tables are kept in your browser only; this page and the published records always show the tables above.

Constants

ConstantValueNote
Annual cost of one engineer$250,000Fully loaded. Editable in the Overview's cost assumptions; dollars rescale, days do not.
Working days per year200
Hours per working day8Used only to show hours.
Cost per engineer-day$1,250$250,000 ÷ 200
Cost per engineer-hour$156.25$250,000 ÷ 1,600 hours
Record costdays × $1,250Rounded to the nearest dollar.

One rate is used for every project and region. No productivity adjustment for AI-assisted coding is applied: nothing in the study measures one, and a modelled discount on a modelled cost would read as a finding.

Severity and CVSS

Severity is the rating the project or its advisory publishes, normalised to four levels: critical, high, moderate, low. The CVSS base score is recorded when the advisory provides one. Neither is used to compute cost — they are shown so cost can be compared against them.

How cost relates to severity

Cost has two parts: D1, measured from the fix, and D2+D3, set by the vulnerability class. Split that way, severity says almost nothing about how big a fix is. The weak link between severity and cost comes from the class table.

Published severityPriced recordsMedian engineer-daysMedian written linesMedian D2+D3
Low8222254
Moderate5,4292244
High4,3002.3333316
Critical1,1013366

Rank correlation with severity (0 = none, 1 = perfect): engineer-days +0.12; written lines +0.08; D2+D3 +0.15. Memory-corruption, JIT and injection classes carry both higher severity ratings and higher reasoning and validation scores, so part of any severity–cost relationship is built into the rubric rather than measured from the fixes.

What counts as written code

D1 measures what an engineer wrote, so the raw diff is filtered first. Across priced records the median fix is 67 changed lines in the raw diff and 28 lines of written code.

Worked example

Node.js CVE-2025-55130 — authentication / authorization bypass. Fix commit 3296b2e734 “lib,permission: require full read and write to symlink APIs”.

FileKindLinesCounted for D1?
lib/fs.jscode32counted
lib/internal/fs/promises.jscode20counted
test/fixtures/permission/fs-symlink-target-write.jstest18excluded
test/fixtures/permission/fs-symlink.jstest18excluded
test/parallel/test-permission-fs-symlink-relative.jstest10excluded
test/parallel/test-permission-fs-symlink.jstest14excluded
  1. The raw diff is 112 lines in 6 files. After exclusions the engineer wrote 52 lines in 2 files.
  2. 52 lines is lines band 3, and 2 files do not raise it — so D1 = 3.
  3. The class sets D2 = 3 and D3 = 3.
  4. Combined 3 + 3 + 3 = 9 → 5 engineer-days → 5 × $1,250 = $6,250 (Medium bucket).

It is also a boundary case: 52 written lines is 2 over the 50-line limit of the band below. At 50 lines or fewer it would score D1 2, combined 8, 3 days ($3,750).

Shared fixes

Sometimes one change fixes several vulnerabilities. Charging its full effort to each would count the same work more than once. A commit is priced once: each record's own price is divided among its commits by the lines they change, and a commit — or the same patch on another branch — that several vulnerabilities share costs the largest share any of them gives it, split equally among them. When the vulnerabilities share exactly the same commits, that is the hardest grading among them, split equally. Today that is 542 shared commit groups covering 1663 records, removing 5736 engineer-days ($7,170,000) that would otherwise be counted twice. A further 244 records are duplicate advisories (one flaw published under two ids): the fix is priced on one id and the other points to it.

Two vulnerabilities whose fixes touch the same file are not a shared fix. Some files are fixed again and again — Firefox's devtools/client/shared/curl.js took three separate vulnerability fixes in one year. Those are recurring vulnerabilities in hotspot files, and each fix is priced.

What is not priced, and why

3,584 of 15,236 records (24%) carry no cost. They stay in the data so “did you find CVE-X?” has an answer, but no estimate is invented for them. Unpriced does not mean the fix cost nothing; it means it cannot be measured from public information. Every total on these dashboards is therefore a floor.

ReasonWhat it meansRecords
No public fix found
no-public-fix-commit
We looked and could not find the fix anywhere public.1,570
Fix not identified by the project
fix-not-publicly-attributed
The fix is in the public repository, but the project does not say which commit it is, so naming one would be a guess.1,141
Fix lives in another repository
out-of-scope-repository
The fix is public, but in a plugin, app or library repository other than the one we measure.406
Priced on a sibling record
fix-shared-with
Fixed by the same change as another vuln. The effort is priced once, on that record.244
Roll-up advisory
rollup-advisory
One advisory covering many bugs at once (for example, Firefox's “memory safety bugs fixed in …”). Kept for coverage, not priced.110
Fix bundled into a release
fix-bundled-in-release
The fix is public but squashed into a release commit with other fixes; any per-vuln split would be invented.65
Fixed by configuration only
configuration-only-fix
The project's remediation is public, but it changed only build, CI or deployment configuration, which is not written code, so there is nothing to price.32
Fixed by documentation only
documentation-only-fix
The project's remediation changed documentation and no code, so there is nothing to price.16

Limitations

Questions

Why can a two-line fix cost several days?

Because D2 and D3 usually outweigh D1. A two-line fix to a JIT compiler scores D1 1 but D2 5 and D3 5: combined 11, 10 days. Most of the work is understanding the bug and proving the fix, not typing it.

Does a critical vuln cost more than a low one?

A little, on average: the median high-severity fix is 2.3333 engineer-days against 2 for low. But not because the fixes are bigger — median written code is about the same from low through high severity. The difference comes from the vulnerability class, which sets D2 and D3, and the classes scored hardest also tend to be rated more severe. Severity is not an input, but part of the relationship is built into the class table. See How cost relates to severity.

What is “tier” in the data?

An exploitability label — T1 primary driver (remote-code-execution-class memory corruption), T2 chain enabler, T3 reachable but limited, T4 hardening — recorded only for Firefox and Tomcat and blank elsewhere. It is not an input to cost and no chart uses it. It is set from the vulnerability class (for Tomcat, class and severity), the same class that sets D2 and D3, so comparing tier with cost mostly compares the rubric with itself.

Does the cost include finding the bug, or shipping the release?

No. Only writing and validating the fix. Discovery, triage, disclosure, release and downstream deployment are outside the model, so the true cost of a vulnerability is higher than the figure shown.

Is AI-assisted coding factored in?

No. The figures are engineer effort without any productivity discount, because nothing in this study measures one.

Can I use a different salary?

Yes. Edit the annual cost in the Overview's cost assumptions. Every dollar figure rescales; engineer-days stay the same, since they do not depend on the rate.

Why is a vuln I know about missing, or shown without a cost?

Missing: see the first limitation — the record set is a floor. Shown without a cost: no public fix could be measured for it. The reasons are listed in What is not priced.

What does “Credited to Anthropic” mean?

The vulnerability's credit names Anthropic or Claude — in the project's own advisory (Firefox), or on the community-maintained list at github.com/patrickmgarrity/Anthropic-Credited-CVEs (checked 2026-10-31, list version e8b88e2a95f2). The credit is often shared with human researchers. 183 records carry it, 176 of them priced (593.5 engineer-days, 2% of the total), in Apache Camel, Apache HTTP Server, Bouncy Castle (C#), Bouncy Castle (Java), Coder, Firefox, Ghost, Gitea, Joomla!, Mastodon, Nuxt, OpenEMR, PCRE2, PostgreSQL, PraisonAI, PrestaShop, Rocket.Chat, Suricata, Symfony, Traefik, Twig, WeKan, Wireshark, ZoneMinder, htslib, libssh2, uutils coreutils. It is a label for cutting the data — the filter on both dashboards — not an input to cost. The list changes often, and the label is refreshed from it from time to time.

Why does one project show far more records than priced records?

Its advisories do not identify the fixing commit, or the fix is not public. 7-Zip has the lowest share: 0% of its records are priced. GitLab publishes no commit reference at all; its records are priced only because we matched each vuln to a commit in its release ourselves, and they are labelled as our inference.