Upgrade Feasibility Index
The Upgrade Feasibility Index (UFI) answers how hard will it be to upgrade by analyzing your actual codebase and producing a single score that quantifies the effort required to apply a security fix.
What is the UFI
The UFI is a composite score between 0 and 10. It combines four independent dimensions, each capturing a different facet of upgrade difficulty:
| Dimension | Weight | What it measures |
|---|---|---|
| Upgrade Complexity | 40% | How disruptive the version bump itself is (major vs. patch, versions skipped) |
| Blast Radius | 30% | How widely the package is used across your codebase (files, modules, lines of code) |
| Complexity Cost | 15% | How complex the affected code is (maintainability, cognitive load) |
| Coupling Risk | 15% | How tightly the affected code is coupled to the rest of the application |
The final score is a weighted sum of these four dimensions. A higher score means the upgrade will likely require more effort, more testing, and more coordination across the team.
Difficulty labels
The raw score is mapped to a human-readable label so you can quickly triage your vulnerability backlog:
| Label | Score range | What to expect |
|---|---|---|
| Easy | 0.00 – 0.25 | Minimal impact. Typically a patch version bump with few or no code changes needed. Safe to upgrade quickly. |
| Moderate | 0.25 – 0.45 | Some effort required. The package may touch several files or involve a minor version bump. Plan some testing time. |
| Hard | 0.45 – 0.70 | Significant effort. The package is widely used, the code is complex, or the version jump is large. Allocate dedicated time and review capacity. |
| Very Hard | 0.70 – 1.00 | Major undertaking. The upgrade touches a large portion of the codebase, involves breaking changes, or affects highly coupled and complex code. Consider a phased approach. |
Upgrade details
This section focuses on the version jump required to fix the vulnerability. It accounts for 40% of the total score and is entirely based on semver distance - it does not depend on how your code uses the package.
| Field | Example | What it tells you |
|---|---|---|
| Change type | minor | Whether the fix requires a patch, minor, or major version bump. A patch bump (e.g. 2.1.3 → 2.1.4) signals backwards-compatible fixes. A major bump (e.g. 2.x → 3.x) signals breaking changes that may require code modifications. |
| Major versions skipped | 2 | When the fix requires jumping across multiple major versions (e.g. v1 → v3), each skipped version compounds the risk of breaking changes and deprecations. Only shown when at least one major version is skipped. |
When all three code-based dimensions (Blast Radius, Complexity Cost, Coupling Risk) score zero - meaning the package is not imported anywhere in your code - the Upgrade Complexity is also set to zero. If the package is not used, upgrading it has no practical impact.
Impact
This section measures how far the effects of an upgrade could spread through your codebase. It accounts for 30% of the total score. A package imported in two files is fundamentally different from one imported in fifty.
| Field | Example | What it tells you |
|---|---|---|
| Affected files | 1 | The number of source files that directly or indirectly depend on the package. This is the scope of code you may need to review and test after upgrading. |
| Affected modules | 1 | The number of distinct modules (top-level namespaces or directories) that import the package. A package used across many modules likely touches multiple team boundaries and deployment units. |
| Lines of code affected | 5.1% | The percentage of your total codebase (by lines of code) that sits in files importing the package. This gives a proportional sense of the upgrade's footprint. |
Code complexity
Even if only a few files are affected, upgrading is harder when those files contain complex, hard-to-understand code. This section captures that cognitive burden and accounts for 15% of the total score.
| Field | Example | What it tells you |
|---|---|---|
| Avg maintainability index | 89 | A composite metric (0 – 171 scale, higher is better) based on Halstead volume, cyclomatic complexity, and lines of code. It estimates how easy the affected code is to maintain. Low values mean dense, hard-to-change code. This is the average across all affected files. |
| Max cognitive complexity | 1 | Measures how difficult a function is to understand by counting control flow breaks, nesting, and logical operators. Unlike cyclomatic complexity (which counts execution paths), cognitive complexity weights constructs by how hard they are for a human to follow. This is the maximum value found across all functions in the affected files. |
| Total comprehension time | 3.5 min | An estimate of how long it would take a developer to read and understand the affected code, derived from Halstead metrics. This helps translate abstract complexity numbers into a tangible time cost. |
Coupling Risk
This dimension evaluates how interconnected the affected code is with the rest of the application. It accounts for 15% of the total score. Tightly coupled code is harder to change in isolation - a modification in one place is more likely to break something elsewhere.
| Field | Example | What it tells you |
|---|---|---|
| Max fan-in | 8 | The highest number of other files or modules that depend on any single affected file. A file with a fan-in of 15 means 15 other files import or reference it - changes to this file have a ripple effect across all of them. |
Affected files
This section lists every source file that imports or depends on the vulnerable package. Each file entry shows per-file metrics that give you a concrete starting point for planning the upgrade:
| Field | Example | What it tells you |
|---|---|---|
| File name | server.js | The source file that imports the vulnerable package. If a class is defined in the file, it is shown as a badge next to the name. |
| Maintainability index | 89 | Per-file maintainability score (higher is easier to maintain). Same metric as the aggregate, but for this specific file. |
| Max cognitive complexity | 1 | The highest cognitive complexity of any function in the file. |
| Comprehension time | 3.5 min | Estimated reading time for the file in minutes. |
| Affected functions | arrow | The list of functions in the file that may be impacted by the upgrade, shown as small badges. |
Use this list to identify which files will need the most attention during the upgrade. Files with low maintainability and high cognitive complexity are where bugs are most likely to hide after a dependency change.
Resolution confidence
The UFI needs to map a package name (e.g. lodash) to the actual import statements in your code (e.g. import _ from "lodash"). This mapping is not always straightforward - some packages use different names for their npm package and their import path.
The confidence level appears next to the UFI score and tells you how reliably the tool was able to resolve this mapping:
| Confidence | Meaning |
|---|---|
| High | The package was resolved via its ecosystem metadata (e.g. the package's registered import path). The code-level metrics are reliable. |
| Medium | The package was resolved via heuristics (e.g. matching the package name against import paths). Metrics are likely accurate but may miss some usages. |
| Unresolved | The tool could not find any imports matching this package. Impact, Code complexity, and Coupling Risk will all be empty, and only Upgrade details (based on version distance) will contribute to the score. |
Using the UFI in practice
The UFI is most valuable when combined with the other enrichment signals (CVSS severity, EPSS exploitation probability, CISA KEV status) to build a complete prioritization picture:
High severity + Easy UFI
The best candidate for immediate remediation. The vulnerability is serious, but the upgrade is straightforward. Fix it now.
High severity + Very Hard UFI
Still urgent, but needs planning. Consider temporary mitigations (WAF rules, feature flags, input validation) while scheduling the upgrade for a dedicated sprint.
Low severity + Easy UFI
Low-hanging fruit for backlog cleanup. Bundle these with other dependency updates in a regular maintenance cycle.
Low severity + Very Hard UFI
Likely not worth the effort right now. Monitor for severity escalation or active exploitation, but do not let this block more impactful work.