Back to glossary

Vulnerability Management

Vulnerability management is the continuous process of finding, prioritizing, fixing, and verifying known vulnerabilities in the software you run.

Also known as Vulnerability management program, Vulnerability management lifecycle, Risk-based vulnerability management, RBVM, Vuln management, VM program

Vulnerability management, often run as a vulnerability management program, is the continuous cycle of inventorying the software you run, matching it against known vulnerabilities, deciding which findings matter, and remediating and verifying them. For open source dependencies, it joins your dependency tree to advisory databases, so it decides where engineering time goes but covers only disclosed flaws.

Finding vulnerabilities is no longer the hard part. 48,185 CVEs were published in 2025, and as of August 17, 2026, the NVD listed 42,353 CVEs as "Not Scheduled" for enrichment, four months after NIST stopped enriching most CVEs. Detection is cheap and abundant. Deciding what to fix, and then changing code without breaking it, is the bottleneck.

Our position: measure a vulnerability management program by exploitable risk removed, not by findings closed. Gate the queue on reachability and known exploitation, fix through the cheapest safe path, and record every decision not to fix as a machine-readable VEX statement. Do not mistake vulnerability management for supply chain defense. Malicious packages rarely receive a CVE, so the loop sees them late or never.

What is vulnerability management?

#

Vulnerability management is the operational loop that turns public vulnerability disclosures into changes in your own systems. Most definitions describe the same stages. Our guide to building a vulnerability management program for open source uses four: scanning, prioritization, remediation, and verification. We put inventory in front of them, because every later stage inherits its errors.

The loop never finishes, because new advisories keep arriving for code you have not touched. NIST's patch management guidance, SP 800-40 Revision 4, states the operating assumption directly: "Patching should be considered a standard cost of doing business and should be rigorously followed and tracked." The same document names four responses to any vulnerability: accept the risk, mitigate it, transfer it, or avoid it by removing the vulnerable software.

The figure follows one real project through the loop. Its only direct dependency is the request HTTP client, version 2.88.2, and every artifact shown comes from the commands later in this article. The table lists what each stage produces and where it fails for open source dependencies.

StageWhat it producesWhere it fails for open source
1. InventoryEvery package and version you run, from lockfiles, SBOMs, and container layersCode run with npx or installed globally, vendored copies, anything outside a manifest
2. MatchFindings: a package version joined to an advisoryMissing or wrong package identifiers, affected ranges that are too narrow or too wide, duplicate aliases
3. PrioritizeAn ordered queueSorting by CVSS severity instead of reachability, exploitation, and exposure
4. RemediateAn upgrade, override, in-place patch, replacement, or recorded acceptanceNo fixed version inside the parent package's range, abandoned packages, breaking changes
5. VerifyA rescan plus evidence the application still worksA clean rescan of a broken build, fixes undone by a later lockfile regeneration

Inventory and matching

#

For application code, the inventory is the resolved dependency tree, including every transitive dependency, usually read from a lockfile or a software bill of materials (SBOM). Lockfile-based inventory has a known blind spot. After the axios compromise, we wrote in The Hidden Blast Radius of the Axios Compromise that "Lockfiles make existing installs deterministic. They do not make new installs safe." Tools run with npx or installed globally never appear in a project's lockfile, so a vulnerability management program that inventories only lockfiles cannot see them.

Matching joins that inventory to advisory records, and vulnerability scanning covers how that join works and fails. For this article, one property matters: advisory data is an input you cannot fully trust. While preparing a patch for the vm2 sandbox escape, CVE-2026-26956, we found that the GitHub advisory listed only vm2 3.10.4 as affected. Our testing confirmed the exploit across 66 vm2 releases, from 0.2.2 through 3.10.4. A scanner that trusted the advisory would have marked every older install as unaffected.

What is risk-based vulnerability management?

#

Risk-based vulnerability management (RBVM) orders remediation by the likelihood and impact of exploitation in your environment, not by severity score alone. It replaces a rule like "fix everything rated 7.0 or higher" with a queue built from reachability, evidence of exploitation, exposure, and how important the affected system is.

Severity-only queues fail for two reasons. The first is volume: nearly 19,000 of 2025's CVEs were rated high or critical, far more than any team can fix on a severity deadline. The second is that the score itself is unstable. In the Commerce Department Inspector General's federal audit of the NVD, cybersecurity specialists produced the same CVSS vector for only 8 of 69 vulnerabilities, or 12%.

For open source dependencies, the strongest risk signal is reachability analysis: whether any call path leads from your code to the vulnerable function. Socket's Full Application Reachability, run with socket scan create --reach, typically marks about 80% of dependency CVEs as unreachable, and more than 90% in some ecosystems, according to our launch post. An unreachable finding is not risk to that application, whatever its score. Vulnerability prioritization covers how to combine reachability with CISA KEV, EPSS, and CVSS in a single queue.

BOD 26-04 put risk-based deadlines into federal policy

#

On June 10, 2026, CISA issued Binding Operational Directive 26-04, "Prioritizing Security Updates Based on Risk." The directive ranks vulnerabilities on four criteria, as CyberScoop reported: whether the asset is publicly exposed, whether exploitation can be fully automated, whether exploitation gives an attacker control of the system, and whether there is evidence of active exploitation. A vulnerability that meets all four must be fixed within three days, and agencies must run forensic triage to check whether they were already compromised.

The KEV catalog shows the effect. We computed the window between dateAdded and dueDate for every entry in catalog version 2026.11.04, which holds 1,768 entries. In 2025, 226 of 245 KEV additions carried a 21-day deadline. Of the 151 entries added since BOD 26-04 was issued, 120 carry a 3-day deadline and 31 carry 14 days. All 97 entries flagged for forensic triage have the 3-day deadline.

The figure shows KEV additions per month in 2026, split by deadline. The same data as a table:

Month added (2026)Entries21-day14-day3-day2- or 5-day
January1715020
February2822042
March2671450
April3102380
May2101371
June (all after June 10)2306170
July2604220
August3109220
September4309340
October3607290

Three of the four criteria map onto data CISA already publishes. CISA's Vulnrichment program attaches SSVC decision points to CVE records: exploitation, automatability, and technical impact.

Bash
$ curl -s https://raw.githubusercontent.com/cisagov/vulnrichment/develop/2024/35xxx/CVE-2024-35195.json \
  | jq '.containers.adp[].metrics[]?.other | select(.type=="ssvc") | .content.options'
[
  { "Exploitation": "none" },
  { "Automatable": "no" },
  { "Technical Impact": "total" }
]

Exposure is the one input no public record can supply, because it depends on how you deploy the software. That is the general shape of risk-based vulnerability management. Public data supplies the vulnerability half of the decision. Only your own inventory and deployment data supply the other half.

Remediation is where vulnerability management stalls

#

Remediation is the stage that consumes engineering time, and most guidance on vulnerability management treats it as "apply the patch." For a transitive dependency, a fixed version helps only if your dependency graph can accept it. The parent package's declared version range decides that, not you.

We reproduced the common worst case. request is a deprecated npm HTTP client, and its last release, 2.88.2, was published on February 11, 2020. On November 5, 2026, we installed it into an empty project with npm 10.9.9 and Node.js 22.23.4, then ran npm audit:

Bash
$ npm init -y && npm install request@2.88.2
$ npm audit
# npm audit report

form-data  <=2.5.5
Severity: critical
form-data uses unsafe random function in form-data for choosing boundary - https://github.com/advisories/GHSA-fjxv-7rqg-78g4
form-data: CRLF injection in form-data via unescaped multipart field names and filenames - https://github.com/advisories/GHSA-hmw2-7cc7-3qxx
No fix available
node_modules/form-data
  request  *
  Depends on vulnerable versions of form-data
  Depends on vulnerable versions of qs
  Depends on vulnerable versions of tough-cookie
  Depends on vulnerable versions of uuid
  node_modules/request

qs  <=6.15.4
Severity: moderate
qs's arrayLimit bypass in its bracket notation allows DoS via memory exhaustion - https://github.com/advisories/GHSA-6rw7-vpxm-498p
qs: Denial of Service via Attacker Controlled isBuffer - https://github.com/advisories/GHSA-4mjr-xmp4-gh2g
No fix available
node_modules/qs

tough-cookie  <4.1.3
Severity: moderate
tough-cookie Prototype Pollution vulnerability - https://github.com/advisories/GHSA-72xf-g2v4-qvf3
No fix available
node_modules/tough-cookie

uuid  <11.1.1
Severity: moderate
uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided - https://github.com/advisories/GHSA-w5hq-g745-h8pq
No fix available
node_modules/uuid

5 vulnerabilities (3 moderate, 2 critical)

npm reports five vulnerable packages from seven advisories, and "No fix available" for every one. The fixes exist on the registry: form-data 2.5.6, qs 6.17.1, tough-cookie 4.1.3, and uuid 11.1.1. None of them satisfies request's declared ranges (form-data ~2.3.2, qs ~6.5.2, tough-cookie ~2.5.0, uuid ^3.3.2). request will never publish a release that widens them. The fifth vulnerable package is request itself. npm's JSON report attaches an SSRF advisory to it, GHSA-p8p7-x288-28g6, which has no patched version at all.

A clean rescan is not a fix

#

npm's dependency overrides force a version anywhere in the tree, ignoring the parent's range. Overriding all four transitive packages looks like a fix:

Bash
$ npm pkg set overrides.form-data=2.5.6 overrides.qs=6.16.0 \
    overrides.tough-cookie=4.1.3 overrides.uuid=11.1.1
$ npm install && npm audit | tail -1
2 moderate severity vulnerabilities

$ node -e "require('request')"
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './v4' is not defined by "exports" in ./node_modules/uuid/package.json
  code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'

The audit dropped from seven advisories to two, and the application stopped loading. request imports uuid/v4, and uuid 11 no longer exports that path. The qs version we first chose, 6.16.0, also carries a newer advisory, GHSA-6pq8-jhm2-2vcw, so one finding was swapped for another. A verification stage that only rescans would have closed three of the four tickets on a service that cannot start.

The working result takes one decision per finding, using the four NIST responses:

FindingDecisionMechanismWhat it does not cover
form-data 2.3.3 (2 advisories)Mitigate by fixingOverride to 2.5.6, same major versionRuns outside request's tested range. We verified multipart POST only.
qs 6.5.5 (2 advisories)Mitigate by fixingOverride to 6.17.1Twelve minor versions past the 6.5 line request declares. Covered by our multipart and cookie tests only.
tough-cookie 2.5.0 (1 advisory)Mitigate by fixingOverride to 4.1.3, two major versions upWe verified a cookie jar round trip. Other cookie APIs are untested.
uuid 3.4.0 (CVE-2026-41907)Accept, documentedVEX statement: not_affectedBecomes false if your own code calls v3() or v5() with a buffer
request 2.88.2 (CVE-2023-28155)AvoidReplace request. No fix will ever ship.Migration cost. The overrides are a bridge, not an end state.
Bash
$ npm pkg set overrides.form-data=2.5.6 overrides.qs=6.17.1 overrides.tough-cookie=4.1.3
$ npm install
added 24 packages, and changed 3 packages in 468ms

$ node multipart-post.js && node cookie-roundtrip.js
200 ok
cookie sent back: sid=abc

$ npm audit | grep -E '^[a-z].*  '
request  *
uuid  <11.1.1

With three overrides, request still sends multipart bodies and returns cookies in our tests, and npm audit reports the two findings we chose to handle differently. The overrides also added 24 packages to the tree, taking it from 47 to 71. Every fix that arrives as a newer upstream version brings code you did not review, and the npm documentation notes that "Overrides are only considered in the root package.json file," so a library cannot use them to fix its users' trees.

Recording a decision not to fix

#

The uuid advisory affects v3(), v5(), and v6() when the caller passes an output buffer, and it states that v4() throws RangeError on invalid bounds instead (GHSA-w5hq-g745-h8pq). request imports only uuid/v4 and calls it with no arguments. That is a not-affected finding, and it belongs in a format a scanner can read, not in a ticket comment. In OpenVEX, it is a single statement:

JSON
{
  "@context": "https://openvex.dev/ns/v0.2.0",
  "@id": "https://example.com/vex/demo-app-2026-11-05",
  "author": "AppSec Team <appsec@example.com>",
  "timestamp": "2026-11-05T21:00:00-08:00",
  "version": 1,
  "statements": [
    {
      "vulnerability": {
        "name": "CVE-2026-41907",
        "aliases": ["GHSA-w5hq-g745-h8pq"]
      },
      "products": [
        {
          "@id": "pkg:npm/demo-app@1.0.0",
          "subcomponents": [{ "@id": "pkg:npm/uuid@3.4.0" }]
        }
      ],
      "status": "not_affected",
      "justification": "vulnerable_code_not_in_execute_path",
      "impact_statement": "uuid is pulled in only by request@2.88.2, which imports uuid/v4. The flaw is in v3(), v5(), and v6() with a caller-supplied buffer."
    }
  ]
}

The label vulnerable_code_not_in_execute_path is one of five fixed justifications in the OpenVEX specification, and a not_affected statement must carry a justification or an impact statement. A scanner that consumes VEX suppresses the finding for this product, and the document records who made the call and when. The risk is the same as any suppression: the statement encodes an assumption about code that will change, so it needs an owner and a date to revisit it.

When no upgrade path exists, a fourth option is to patch the vulnerable function inside the version you already run. Socket's Certified Patches do this: a reviewed, minimal diff stored in your repository under .socket/ and applied during the build, with no version change and no new upstream code. The trade-off is trust in the patch author's understanding of the bug, which is why the vm2 range error above matters. We found it while building one of these patches.

Our verdict on remediation mechanisms: upgrade inside the declared range whenever one exists. Override only to a fixed version with tests that exercise the parent package. Patch in place when the parent is abandoned or the upgrade drags in a large new subtree. Schedule a replacement for any abandoned package, because no override fixes a flaw in the package itself. Use VEX only for findings you can show are unreachable, and give every statement an owner.

Which vulnerability management metrics mean anything?

#

Most vulnerability management metrics measure activity, not risk. Finding counts depend on the counting unit: the same request project is 5 vulnerabilities in npm's summary line and 7 advisories once each package's entries are expanded. A dashboard that changes units moves by 40% with no change in exposure.

Mean time to remediate (MTTR) rewards closing easy findings, and unreachable findings are the easiest to close. Deadlines keyed to CVSS tiers, such as critical in 7 days and high in 30, send engineers after severity instead of exposure. Our own 2024 program guide used CVSS tiers as a starting policy for a 20-developer company and said reachability becomes essential as volume grows. We now think teams should key deadlines to reachability and exploitation from the start.

Three numbers track risk better. The first is time to remediate reachable findings that have evidence of exploitation. The second is the share of open findings with a recorded decision: a fix, a VEX statement, or an accepted risk with a named owner. The third is the count of findings with no fix path, which is the real backlog. Regulators are moving to exploitation-based clocks as well. Since September 11, 2026, the EU Cyber Resilience Act requires manufacturers to send an early warning within 24 hours of becoming aware of an actively exploited vulnerability in their product.

Vulnerability management does not stop malicious packages

#

Vulnerability management assumes the dangerous thing is a disclosed flaw in legitimate code. A malicious package is working code doing what its author intended. It reaches the vulnerability management loop only after someone files a malware advisory, and by then every install that ran its install script has already executed the payload. In the axios compromise, Socket's malware detection flagged the malicious dependency plain-crypto-js@4.2.1 within six minutes, as one of our advisors noted.

That advisor, Brad Arkin, who ran security at large enterprises before advising Socket, put the mismatch in one line: "Traditional vulnerability management is a forensic instrument." It answers where you used a package and which versions, which is the right question weeks after a compromise and the wrong one while it is happening. Malware needs a control before install that inspects what the package actually contains. The two problems also pull against each other. A cooldown that refuses package versions younger than seven days blocks fresh malicious releases, and it also delays every security fix, while the window from patch to working exploit is now measured in hours.

The scarce resource in vulnerability management has moved from detection to safe change. AI-assisted discovery is raising disclosure volume, and federal deadlines for the most dangerous KEV entries have dropped from 21 days to 3. Neither helps when the fixed version sits outside the range of a parent package nobody maintains. The programs that keep up will be the ones that can make a small, reviewable change to the code they already run, verify that the application still works, and do it in hours.