Safeguard
Product•

Why Dependency Upgrade Pull Requests Sit Unmerged, and How to Fix It

Upgrade PRs stall because reviewers cannot tell what will break or why it matters. Group by root package, rank by KEV and reachability, attach evidence.

Safeguard Security Team
39 min read

Dependency upgrade pull requests sit unmerged because the reviewer cannot answer two questions quickly: what will this break, and why does it matter more than the other forty open ones. Fix the merge rate by grouping upgrades by root package, ranking them by known exploitation, exploit probability and reachability, choosing a conservative upgrade strategy per repository, and putting the evidence of what changed into the pull request body so review takes minutes instead of a research project.

Below: each cause, what the standards say, a ranking model built on free public data, and how Safeguard handles the same job, including what it does not do.

Key takeaways

  • An update bot that opens pull requests is not the same as a team that merges them. The OpenSSF Scorecard check for update tooling says plainly that it cannot tell whether a tool's pull requests are merged.
  • Reviewers hesitate for concrete reasons: no tests cover the changed code path, the version jump is a major one, five pull requests touch the same root package, and nothing tells them which pull request carries real security weight.
  • Semantic Versioning is a promise made by maintainers, not a guarantee. Version 0.y.z carries no stability promise at all, and behaviour that nobody documented still breaks callers.
  • Rank open upgrades by CISA KEV listing first, then EPSS probability, then whether your code reaches the vulnerable function. That ordering follows CISA's own reasoning and FIRST's definition of EPSS.
  • One upgrade of a root package often closes several advisories at once. NIST's SSDF says a single remediation can address multiple vulnerabilities; group your pull requests that way.
  • Safeguard's autonomous remediation and Griffin fix pull requests (single and bulk, one pull request per repository) are GA and ship switched off, with every category set to Manual. Strategy choices are Safest, Balanced, Aggressive and Smart, and they are saved but not applied until the master toggle is on.
  • Safeguard's reachability analysis and prioritisation with EPSS and KEV are GA.
  • SCA and vulnerability management are GA. The Safeguard CLI and IDE extensions are GA. Ticketing integrations such as Jira are GA. Fork and patch is GA.

Why dependency update pull requests sit unmerged

The usual arc: the bot opens a wave of pull requests, people merge the easy ones, and by the second month dozens sit open, rebased many times and ignored. Then an advisory lands for a package whose upgrade pull request has been open for three months. The cause is rarely laziness. The pull request, as delivered, does not give a reviewer enough to say yes.

What makes a reviewer hesitate on an upgrade PR?

There is published research on this. A study by He and colleagues in IEEE Transactions on Software Engineering (arXiv preprint, last revised May 2023) examined the most visible dependency update bot on GitHub through repository data and a developer survey. It reports that developers are "suspicious of updates performed by dependency management bots" and tired of the notifications. Projects did reduce technical lag after adopting the bot, but its compatibility scores were too scarce to reduce that suspicion, developers tended to configure it to send fewer notifications, and 11.3% of the projects studied had dropped it for alternatives.

The OpenSSF Scorecard project makes a related point. Its Dependency-Update-Tool check rates the absence of an update tool as a high risk, but its documentation states that it "does not ensure that the tool is run or that the tool's pull requests are merged." Having the bot is a box you can tick. Merging what it opens is the actual control.

The hesitation comes down to a short list of causes.

  1. No tests on the changed path. None of the tests exercise the code that calls the upgraded library, so a green CI run says nothing about whether date parsing, retry behaviour or serialisation changed. The reviewer knows this.
  2. Major version jumps. Moving a library from 3.x to 5.x is a migration, not a review. It sits until someone schedules that work, which is often never.
  3. Many pull requests for one root package. A framework upgrade arrives as one pull request for the framework, three for its plugins and two for transitive packages it pins. Merging one alone may not resolve. Reviewers wait for the set, which never arrives as a set.
  4. No security signal to rank them. Forty open pull requests look the same. One fixes a vulnerability in CISA's Known Exploited Vulnerabilities catalog that is reachable from a public endpoint; thirty nine are drift. Without a ranking, people work top to bottom.
  5. Lockfile churn. Every merge invalidates the lockfile changes in every other open upgrade pull request. The bot rebases, CI reruns, and the queue never drains.
  6. No owner. A bot opened it, so it is nobody's assignment. Repository owners assume the platform team handles it, and the reverse.
  7. No evidence in the description. "Bumps library from 2.4.1 to 2.6.0" with a release link leaves the reviewer to read the changelog and find the call sites. That is twenty minutes per pull request, multiplied by the queue.

How do semantic versioning promises and real-world breakage differ?

Semantic Versioning 2.0.0 sets out the contract most ecosystems lean on. Given a version number MAJOR.MINOR.PATCH, the major number goes up for incompatible API changes, the minor number for backward compatible new functionality, and the patch number for backward compatible bug fixes. Version 1.0.0 defines the public API, and the numbering after that depends on how that API changes.

That contract is useful and widely followed, but there are four places where it does not protect a reviewer.

Version zero promises nothing. The specification says major version zero is for initial development and anything may change at any time. Many mature packages still sit on 0.y.z. npm's range rules reflect this: ^0.2.3 means at least 0.2.3 and below 0.3.0, while ^1.2.3 means below 2.0.0. For 0.x packages the package manager already treats a minor bump as potentially breaking.

The public API is whatever the maintainer says it is. The Cargo book's chapter on compatible and breaking changes for Rust libraries says these are guidelines, not rules every project will obey, and defines a possibly breaking category that some projects treat as minor and others as major. Other ecosystems have the same grey area without writing it down.

Callers depend on behaviour nobody promised. Hyrum's Law: with enough users of an API, every observable behaviour will be depended on by somebody, whatever the contract says. Error text, key ordering, default timeouts and how a parser handles malformed input are all observable. A patch that changes them is semver compliant and can still break you.

Mistakes happen and are fixed forward. The Semantic Versioning FAQ covers the case where a maintainer accidentally releases a breaking change as a minor version: fix it and release a new minor version that restores compatibility, and never modify a published release. So a breaking minor can and does reach registries; the correction comes in the next release.

Some ecosystems build the contract into the tooling. Go modules, for example, require a major version from v2 onward to change the module path (the Go documentation shows example.com/mymodule/v2), which makes a major upgrade a new import path rather than a silent change. The Go docs also say a v0 version carries no stability or backward compatibility guarantee.

Version jumpWhat the maintainer promisedWhat still breaks in practiceReview effort
Patch, 1.x and aboveBackward compatible bug fixesBehaviour callers relied on without a contract; fixes that change edge case outputLow, if tests cover the call sites
Minor, 1.x and aboveBackward compatible new functionalityDeprecations that start warning, new transitive dependencies, possibly breaking changesLow to medium
Any bump on 0.y.zNothing; anything may changeAnythingTreat as major
MajorIncompatible API changes expectedRemoved and renamed APIs, changed defaults, new runtime requirementsMigration, not review

The practical lesson: semver tells you where to look first, not whether to skip looking. A good upgrade pull request pairs the version jump with evidence about the call sites that use the library, which is what the later sections cover.

What the standards say about keeping dependencies current

Several primary sources treat upgrade work as part of vulnerability response, not hygiene.

NIST SP 800-40 Rev. 4 (April 2022), the guide to enterprise patch management planning, frames patching as preventive maintenance and a cost of doing business. It lists four risk responses: accept, mitigate, transfer and avoid. Upgrading to a version without the vulnerability removes it without removing functionality, though NIST notes that is sometimes not viable, for example when no patch exists yet or the software is end of life. Its life cycle is know, plan, and execute, where execution means prepare (including testing the update), implement, and verify. It also asks for maintenance plans covering routine patching, emergency patching, emergency mitigation and unpatchable assets, plus a process for exceptions.

NIST SP 800-218, the Secure Software Development Framework (February 2022), puts this into practice RV.2, assess, prioritise and remediate vulnerabilities. Task RV.2.1 is to analyse each vulnerability to gather enough information about risk to plan its remediation, with an example of risk calculations based on exploitability and impact. Task RV.2.2 is to plan and implement risk responses, with examples that include a risk based decision on whether each vulnerability will be remediated or handled another way, temporary mitigation when no permanent fix exists yet, and updating records of risk responses and approved exceptions. One of the RV.2.2 examples notes that a single remediation could address multiple vulnerabilities, which is the case for grouping upgrade pull requests by root package. Task PW.4.4 covers verifying that acquired open source components meet your requirements throughout their life cycles, including checking regularly for publicly known vulnerabilities in them.

OWASP Top 10 2021, A06 Vulnerable and Outdated Components, lists the conditions under which you are likely exposed. Two of them describe a stalled upgrade queue: not upgrading the underlying frameworks and dependencies in a risk based, timely fashion (OWASP notes this commonly happens when patching is a monthly or quarterly task under change control), and developers not testing the compatibility of updated or patched libraries.

CISA Binding Operational Directive 26-04, "Prioritizing Security Updates Based on Risk," issued 10 June 2026, is the current federal rule. It binds federal agencies, but its logic travels. It revoked and superseded BOD 22-01, the 2021 directive that created the Known Exploited Vulnerabilities (KEV) catalog and set fixed two-week deadlines for it. BOD 26-04 replaces the single number with timelines built from four factors: public exposure of the asset, KEV status, whether exploitation can be automated, and partial or total control. The timeline moves as facts change; a KEV addition shortens it. Our post on BOD 26-04's four factors goes deeper.

The case for leading with exploitation is older. CISA's explanation for BOD 22-01 was that, based on data going back to 2019, less than 4% of all known vulnerabilities had been used by attackers in the wild, so focusing on that set beats working through everything by CVSS.

Together they describe the job an upgrade queue should do: know which upgrades fix real risk, decide the response, test, ship, and record exceptions. A queue of identical bot pull requests does the first step at most.

Which open upgrade PRs carry security weight, and how do you rank them?

Most open upgrade pull requests are version drift: no advisory, no deadline. A minority fix a published vulnerability. A smaller set fix a vulnerability that is being exploited. Your ranking should separate those groups before anyone reviews anything.

Three public signals do most of the work.

CISA KEV. CISA describes the catalog as the authoritative source of vulnerabilities that have been exploited in the wild, and says organisations should use it as an input to their vulnerability management prioritisation. If an open pull request fixes a KEV listed CVE, exploitation is not hypothetical. That pull request goes to the top.

EPSS. FIRST's Exploit Prediction Scoring System estimates the probability that a published CVE will be exploited in the wild in the next 30 days. It publishes a score from 0 to 1 for every CVE, updated daily, with percentiles, and the data is free. FIRST's FAQ explains how to read it: among many vulnerabilities scored around 0.05, you would expect exploitation activity for about 5 in 100. EPSS is a probability across a population, not a verdict on one CVE, so use it to order work, not to dismiss a fix.

Reachability. A vulnerable function that your code never calls is still worth upgrading, but it is less urgent than one on a request path. Reachability analysis builds a call graph from your code and dependencies and checks whether a path leads to the vulnerable function. It has known blind spots: reflection, dynamic dispatch, native code and data driven vulnerabilities can defeat static analysis, so "unknown" should be treated as potentially reachable, not as safe.

A simple tiering that a platform team can apply to an open queue:

TierConditionSuggested handling
1Fixes a KEV listed CVE, code path reachable or unknownMerge this week; owner assigned by name; exception only with written approval
2Fixes a KEV listed CVE, unreachable; or EPSS high and reachableMerge in the current sprint
3Fixes a CVE with low EPSS, reachableBatch into the next scheduled upgrade window
4Fixes a CVE, unreachable and low EPSSBatch with routine drift; review monthly
5No advisory, version drift onlyGrouped, scheduled, and capped

Where you draw the EPSS line is your call. FIRST does not publish a single threshold, and the right cut depends on how much capacity you have. Write the threshold down in your vulnerability management policy so reviewers are not making it up per pull request, which is also what SSDF RV.2.2 asks for when it talks about a risk based decision and recorded exceptions.

Two cautions: absence from KEV is not evidence of safety, and CVSS alone is a weak ranking key. BOD 26-04 keeps known exploitation in the lead and adds technical impact alongside KEV status.

When should one upgrade close several advisories, and how do you group PRs by root package?

The single most effective change to an upgrade queue is to stop treating each pull request as independent. A typical tree has a handful of root packages (frameworks, SDKs, build tools) that pull in most of the transitive packages. When an advisory lands on a transitive package, the clean fix is often an upgrade of the root package that brings in a fixed version, not a direct bump of the transitive package.

Find the root package. Every ecosystem has a way to ask why a package is installed. In npm, for example:

npm ls vulnerable-package
npm explain vulnerable-package

The output shows each path from your direct dependencies down to the vulnerable package. If every path goes through one framework, the framework is your root package and that is the pull request worth reviewing.

Decide whether one upgrade closes several advisories. Group when all of these hold:

  • The advisories sit in packages that share a root package in your tree.
  • A single version of the root package resolves all of them.
  • That root version is within the upgrade strategy you allow for this repository (more on strategies below).
  • The combined change can be tested by one CI run, without needing a migration.

Split when any of these hold:

  • One of the advisories is KEV listed and the grouped change includes a major upgrade. Ship the urgent fix alone first, ideally with the smallest version change that resolves it, and do the major upgrade separately.
  • The group crosses ownership boundaries, for example a shared library and the service that consumes it.
  • The group mixes production and development dependencies. A test runner upgrade should not block a runtime security fix.

When the root package has no fixed release yet. Package managers give you a way to force a transitive version. npm documents overrides in package.json for exactly this purpose, with replacing a version that has a known security issue as its first example. Other ecosystems have equivalents (dependency resolution rules, constraints files, replace directives). Treat an override as a temporary mitigation in the SSDF sense: record it, give it an expiry, and remove it when the root package ships a release that includes the fix. Overrides that outlive their reason are a common source of the next round of confusing upgrade pull requests.

Group the pull requests themselves. Most update bots can group related updates into one pull request by pattern or by update type. Use that for drift (tier 5), and keep security fixes (tiers 1 and 2) in their own pull requests so they are never held behind a routine batch. A separate post covers grouped dependency update pull requests across many directories in a monorepo.

Which upgrade strategy fits which repo: patch only, minor, or major?

Set an upgrade strategy per repository, write it down, and configure your tooling to match.

Repository profileStrategyWhy
Low test coverage, revenue critical, few maintainersPatch only (backward compatible fixes)Smallest blast radius; the tests cannot catch much, so keep the change small
Good coverage on call sites, active teamMinor and patchPicks up fixes and new features within a major line; breaking changes should be rare
Library or SDK others depend onMinor and patch, with majors planned per releaseYour own consumers inherit your choices; plan majors with your own release
Prototype, internal tool, or a service you are actively rewritingInclude majorsCatching up is cheaper now than later
Mixed: some packages pinned for a reasonPer package rulesPin the few with documented reasons; everything else follows the repo default

Three rules make strategies work.

  1. The strategy limits the automatic path, not the security path. If a KEV listed fix requires a major upgrade in a patch only repository, the strategy should not hide it. It should route it to a human with a deadline.
  2. Revisit the strategy when coverage changes. A repository that adds integration tests around its HTTP client can move from patch only to minor and patch for that dependency.
  3. Treat 0.y.z as major regardless of strategy. The semver rules and the npm caret rules both say so.

For a small team, the queue size question matters as much as the strategy. See how many dependency update pull requests a small project can absorb and work in progress limits for open fix pull requests for capacity models.

What evidence in the PR body speeds review?

The fastest way to raise the merge rate is to answer the reviewer's questions before they ask. A good upgrade pull request body covers six things.

  1. Why this pull request exists. The advisory IDs it closes, the KEV status, the EPSS score on the day it was opened, and whether the vulnerable code path is reachable. If it is drift only, say so.
  2. What changed upstream. The relevant changelog entries between the old and new version, not a link to the whole changelog. The Keep a Changelog convention groups entries as Added, Changed, Deprecated, Removed, Fixed and Security, which makes this easier when maintainers follow it. Changed, Deprecated and Removed are the ones reviewers need.
  3. Where your code touches it. The files and functions that import or call the upgraded package. If the vulnerable function is reachable, the call path.
  4. What the version jump is. Patch, minor or major, and whether the package is on 0.y.z.
  5. What was tested. The CI result, and specifically whether any test exercises the call sites in item 3. If none do, say so; that is useful information.
  6. What else this closes. Other open pull requests that this one supersedes, so the reviewer can close them in the same sitting.

A template you can paste into your bot configuration or your own tooling:

## Why
Closes: CVE-XXXX-NNNNN (KEV: yes/no, EPSS: 0.xx on YYYY-MM-DD)
Reachability: reachable via src/api/upload.ts -> parser.parse()

## Version change
some-framework 4.17.1 -> 4.19.2 (minor)
Transitive: parser 1.2.0 -> 1.2.4 (patch)

## Upstream changes that matter here
Changed: default body size limit lowered
Deprecated: legacy callback API (we do not use it)

## Our call sites
src/api/upload.ts, src/api/import.ts

## Tests
CI green. Tests covering call sites: upload.test.ts (yes), import.test.ts (none)

## Supersedes
#412, #415, #418

A reviewer can approve that in minutes or reply with a specific concern. Our five minute review checklist for a dependency update pull request goes through the reviewer's side of the same exchange.

How Safeguard does this job, step by step

The capabilities involved are SCA and vulnerability management (GA), reachability analysis and prioritisation with EPSS and KEV (GA), and autonomous remediation with Griffin fix pull requests, single and bulk (GA, ships switched off with every category set to Manual). The flow follows Safeguard's docs for AI Remediate, Vulnerabilities and Vulnerability Prioritization.

Step 1: Connect repositories and let continuous scanning build the inventory

Safeguard's SCA builds a full transitive inventory across npm, PyPI, Maven and Gradle, Go, Cargo, NuGet, Composer and Bundler, plus container layers. The docs say projects are scanned daily and re-evaluated when new CVEs are published. Vulnerability data comes from NVD, GitHub Security Advisories, OSV, CISA KEV and vendor bulletins.

To start from a developer machine, the Safeguard CLI (GA) installs on macOS and Linux as the CLI docs show:

curl -fsSL https://cli.safeguard.sh/install | bash
safeguard

Inside the interactive terminal, type /login to authenticate and /scan . to scan the current folder. safeguard scan builds an SBOM and matches it against vulnerability databases.

Step 2: Rank what is open by exploitation and reachability

In the platform, the Vulnerabilities tab groups findings into Critical, High, Medium, Low and Exploitable, where Exploitable means known active exploitation in the wild. Each vulnerability shows its CVE ID, CVSS score, EPSS score, whether it is actively exploited, the affected component and version, the fixed version and the reachability status.

The Vulnerability Prioritization docs describe a Priority column and a Reachability column on the same table, sorted by priority by default, and filters such as:

reachable:true
kev:true
epss:>0.3
env:production reachable:true kev:true

The last one is the docs' example for the most urgent backlog. Safeguard's docs say that reachability classifies each vulnerability as reachable, conditionally reachable, unreachable or unknown, and that unknown is treated conservatively as potentially reachable. Safeguard's docs also say reachability filtering typically removes 60 to 80% of findings from the urgent queue; treat that as Safeguard's stated figure, not a guaranteed result for your code.

Reachability support varies by language. The docs list static and dynamic reachability as GA for JVM languages, Python, JavaScript and TypeScript, Go, Rust, C and C++, and C# and .NET. Static reachability covers Ruby and PHP, and Swift and Objective-C are covered for both static and dynamic reachability.

This is the tiering table from earlier applied to your real inventory.

Step 3: Check the fix options before opening anything

Click a vulnerability and choose View Fix. The docs say this shows the upgrade options and any breaking change warnings. This is where you decide whether the fix is a patch, a minor upgrade, or a major one, and whether the root package or the transitive package should move.

If a finding does not apply, the same page has Mark False Positive (with a justification, submitted for approval if your policy requires it) and Accept Risk (with an expiry date and a business justification, submitted for approval). Those two actions are the recorded exceptions that NIST SP 800-40 and SSDF RV.2.2 ask for.

Step 4: Open a single fix pull request

For one vulnerability, the AI Remediate docs give four steps:

  1. Navigate to the vulnerability.
  2. Click AI Remediate.
  3. Review the proposed changes.
  4. Click Create Pull Request.

Behind that, Griffin runs five stages: it analyses the vulnerability and your codebase, works out the safest upgrade path, assesses impact by checking for breaking changes and compatibility, creates the pull request, and runs automated tests to validate the fix. For dependency upgrades, the docs say Griffin upgrades the vulnerable package, handles transitive dependency conflicts, updates lock files and aims to keep compatibility with existing code.

The pull request body is where this answers the reviewer. The docs list what auto-generated pull requests include: a title with the CVE reference, a description of the vulnerability, a summary of the changes, breaking change warnings if any, test results if tests are configured, and links to the relevant advisories. That maps to items 1, 2, 4 and 5 of the evidence list above. Your own reviewers still own item 3 where reachability does not cover the language, and item 6 if bot pull requests from other tools are also open.

Step 5: Read the breaking change rating

Every fix gets a breaking change rating from Griffin. The docs define four levels:

RatingMeaning in the docsSuggested review
SafeNo breaking changes expectedNormal review; good candidate for routine merge once you trust the flow
MinorMinor API changes, low riskRead the summary and check the call sites
MajorSignificant changes, review recommendedSomeone who knows the library reviews
CriticalHigh risk of breaking, manual review requiredTreat as a migration; see the section on major upgrades below

Breaking change detection reduces upgrade risk; it does not remove it. It is an assessment, and Hyrum's Law still applies to behaviour that no changelog mentions.

Step 6: Fix many vulnerabilities at once, one pull request per repository

For a backlog, the docs describe bulk remediation:

  1. Select the vulnerabilities to fix.
  2. Click AI Remediate Selected.
  3. Griffin batches compatible fixes.
  4. Review all changes.
  5. Create the pull requests, one per repository.

There is also a page level option: the AI Remediate button at the top of the Vulnerabilities page analyses all fixable vulnerabilities, shows a remediation plan, and creates pull requests after you approve. One pull request per repository is the grouping rule from earlier applied automatically: the reviewer gets one change per repository that closes several advisories, instead of one per advisory. For more on how this behaves across a large estate, see how bulk fix pull requests work across many repositories.

Step 7: Choose a strategy per category, then decide what runs on its own

Autonomous remediation is organised by category. For the Vulnerabilities and Dependencies categories, Safeguard offers four strategies:

StrategyWhat it doesFits
SafestBackward compatible fixes onlyPatch only repositories, low coverage, critical services
BalancedMinor version updates and patches, minimal breaking changesMost actively maintained services
AggressiveAll available fixes, including major version updatesInternal tools, prototypes, rewrites
SmartThe model picks per item based on context, risk and impactTeams that want per item judgement and will review the choices

Autonomous remediation ships switched off, and every category starts at Manual. The strategy you pick is saved, but it is not applied until you turn on the master toggle. That default is deliberate: you decide how much runs on its own and what still needs a human approval.

The AI Remediate settings in the docs add the controls that matter for merge rate: Auto-Create PRs (create pull requests automatically for safe fixes), Require Approval (manual approval before pull requests are created), Test Integration (run tests before creating pull requests), Breaking Change Policy (how to handle breaking changes) and Branch Naming. A reasonable starting configuration is Safest or Balanced, Require Approval on, Test Integration on, and a breaking change policy that never auto-creates anything rated Major or Critical. The docs' own best practices say the same: enable tests, start with safe fixes, review major changes, do not auto-merge breaking changes, and track fix success rate.

Step 8: Match the IDE to the same strategy

The Safeguard IDE extensions (GA) have their own three strategies, Safe, Balanced and Aggressive, with Balanced as the default, set through safeguard.remediationStrategy in VS Code and Cursor or a picker in the JetBrains quick fix flow. Auto fix on save is off by default. Matching the IDE strategy to the repository's platform strategy keeps a local fix and the platform's pull request from disagreeing about how far to move a version.

Step 9: Keep the fixed version fixed

Merging the upgrade is half the job. The other half is making sure the vulnerable version does not come back through a lockfile regeneration or a new dependency. Safeguard policies and gates (GA) evaluate findings in the platform, and the docs list gate actions Block, Warn and Notify, with approval handled through exceptions. A policy that blocks reachable, KEV listed vulnerabilities in production is the docs' own example. The stop at the merge step is covered in more depth in stopping vulnerable dependencies at five checkpoints.

If you track remediation in a ticketing system, Safeguard's ticketing integrations such as Jira are GA. For upgrades, a reviewable pull request is usually the better unit of work; see getting developers to fix findings without a ticket queue.

What to do with PRs that genuinely need a major upgrade or a rewrite?

Some upgrade pull requests will never merge because the real work is a migration. Close them and replace them with a decision.

1. Separate the security fix from the migration. Many maintainers patch the previous major line for a while after a new major ships. If a fixed version exists on your current major, take it now with the Safest strategy and schedule the major separately.

2. If no backport exists, mitigate and record. NIST SP 800-40 Rev. 4 lists mitigation options other than upgrading, such as disabling a vulnerable feature or adding controls around the vulnerable asset. SSDF RV.2.2 asks you to add a temporary mitigation to the plan when a permanent fix is not yet available. In a dependency tree that might be an override to a patched transitive version, turning off the feature that reaches the vulnerable code, or input validation in front of it. Record it as an accepted risk with an expiry date, so it comes back for review.

3. Plan the major as a project. Give it an owner, a branch, a test plan for the call sites, and a target release. Read the maintainer's migration guide. For Go modules, remember a v2 is a new module path, so the change is mechanical but touches every import.

4. When the library is abandoned, replace it. NIST SP 800-40 notes that a vendor that no longer supports software will never release a patch for it. The same is true of an unmaintained package. The choices are a maintained alternative, a fork you maintain yourself, or a hardened build from someone who maintains it for you.

5. Use the breaking change rating to sort, not to decide. In Safeguard, fixes rated Major or Critical are the candidates for this path. They still need a person.

Requirement vs what Safeguard does vs what you still own

Requirement or needWhat Safeguard doesWhat you still own
Know which components and versions you run (SP 800-40 life cycle step 1; SSDF PW.4.4)SCA builds a full transitive inventory and rescans daily (GA)Connecting every repository; build artefacts that do not come from a scanned repo
Analyse each vulnerability's risk (SSDF RV.2.1)EPSS, KEV, reachability and context combined into a priority (GA)Your EPSS threshold and business context; judgement on unknown reachability
Decide and record a response (SSDF RV.2.2; SP 800-40 exceptions)Mark False Positive and Accept Risk with justification, expiry and approvalWho approves; how long exceptions last
Test the update before shipping (SP 800-40 prepare step; OWASP A06)Breaking change detection, test integration and test results in the pull request (GA)The test suite itself, and tests on the call sites that matter
Group fixes so one change closes several advisories (SSDF RV.2.2 example)Bulk remediation batches compatible fixes, one pull request per repository (GA)Splitting urgent fixes from migrations where a group would mix them
Remediate exploited vulnerabilities on risk-based timelines (BOD 26-04 for agencies)KEV filters and priority ordering; fix pull requests on demand (GA)Merging, deploying and verifying in production
Keep the fixed version from returningPolicies and gates with Block, Warn and Notify (GA)Wiring the gate into the merge path and release process

What Safeguard does not do

  • It does not replace your test suite. Test Integration runs the tests you have. If no test exercises the code that calls the upgraded library, a green result tells you little, from Safeguard or anyone else.
  • Breaking change detection reduces upgrade risk; it does not remove it. Ratings are an assessment from the changes Griffin can see. Behaviour that callers depend on without a documented contract can still change in a release rated Safe.
  • Nothing runs on its own until you turn it on. Autonomous remediation ships switched off with every category at Manual. Strategies you select are saved but not applied until the master toggle is on, so a team that sets Balanced and forgets the toggle will still be fixing by hand.
  • Fix pull requests do not cover every ecosystem. The AI Remediate docs list JavaScript (npm, yarn, pnpm), Python (pip, poetry, pipenv), Java (Maven, Gradle), Go modules, Rust (Cargo), Ruby (Bundler), .NET (NuGet) and PHP (Composer). Packages outside those, such as system packages in a base image or vendored code without a manifest, need another route.
  • Reachability is not uniform across languages. Dynamic dispatch, reflection and native code produce "unknown" results that should be treated as reachable.
  • It does not merge or deploy for you by default, and it does not decide your risk appetite. Merging, rolling out, and verifying the fix in production remain your process. So does the EPSS threshold, the exception policy and who approves it.
  • It does not migrate major versions for you. A fix rated Major or Critical is a signal to plan a migration, not a promise that the pull request is ready to merge.
  • Ticketing integrations and fork and patch are generally available. If you plan around either, confirm coverage first.

Common mistakes

  • Measuring the bot instead of the queue. Having an update tool enabled satisfies a checklist. The useful measures are days open for security relevant upgrades and the count of stale pull requests.
  • Ranking by CVSS alone. A high CVSS score on an unreachable development dependency can matter less than a medium score on a KEV listed, reachable runtime package. KEV, EPSS and reachability should lead.
  • Bundling a security fix into a major upgrade. The urgent fix then waits for the migration. Ship the smallest change that resolves the advisory first.
  • Treating 0.y.z minor bumps as safe. The specification makes no promise for version zero, and npm's caret rules already treat them as breaking.
  • Leaving overrides in place forever. A forced transitive version is a temporary mitigation. Give it an expiry and remove it when the root package catches up.
  • Turning on full automation on day one. Start with Safest or Balanced, require approval, run tests, and widen once you have seen real pull requests.
  • Letting migrations sit as pull requests. Close them and schedule the work; a pull request nobody will merge trains the team to ignore the rest.
  • Grouping across owners. A grouped pull request that needs two teams to approve will wait for the slower one.

FAQ

Why do dependency update pull requests never get merged?

Reviewers cannot see what will break or why it matters. The pull request lacks tests on the changed path, mixes major and minor jumps, duplicates others for the same root package, and carries no security signal.

Should I auto-merge patch updates from a dependency bot?

Only where tests cover the call sites and the package is 1.0.0 or later. Semver promises compatible patches, but undocumented behaviour and accidental breaking releases mean tests are the real check.

How do I prioritise dependency updates that fix vulnerabilities?

CISA KEV listed fixes first, then high EPSS, then reachable ones, then the rest. EPSS is the probability of exploitation in the next 30 days.

Does a minor version bump ever break things?

Yes. Version zero packages promise nothing, maintainers sometimes ship breaking changes by mistake, and callers depend on undocumented behaviour.

How do I group dependency updates by root package?

Use your package manager's explain or tree command to find the direct dependency that pulls in each vulnerable package. Upgrade it once and close the pull requests it supersedes.

Is Safeguard's autonomous remediation on by default?

No. It ships switched off with every category set to Manual. Pick a strategy per category (Safest, Balanced, Aggressive or Smart) and turn on the master toggle when you want it to act on its own.

Can Safeguard open one pull request per repository for many vulnerabilities?

Yes. Bulk AI Remediate (GA) batches compatible fixes and creates one pull request per repository.

What if the only fix for a vulnerability is a major version upgrade?

Look for a backported fix on your current major first. If there is none, mitigate, record an accepted risk with an expiry, and plan the major as a project.

Does reachability analysis mean I can ignore unreachable vulnerabilities?

No, only that you can schedule them later. Reachability has blind spots, and Safeguard's docs say "unknown" results are treated as potentially reachable.

Try it on your own repositories

Install the Safeguard CLI or the desktop app from safeguard.sh/download, scan a repository with an open upgrade backlog, and compare the ranked list with the order your pull requests are sitting in. The full docs are at docs.safeguard.sh/docs.

When the fix is a version bump, or when there is no fix yet

Most stalled upgrade pull requests have a fixed version waiting; the problem is review and ranking, which the first part of the block below addresses. Some do not have a fix upstream at all, and that is where waiting for a maintainer becomes the bottleneck rather than the review queue.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real CLI session. After installing, the developer runs safeguard to open the interactive terminal and asks it to fix the lodash CVE in the repository. The assistant reads the finding and the advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, prints a summary and pushes nothing; the session then shows /permissions, /model and /scan. That is a single upgrade done the way this post recommends: the smallest version change that resolves the advisory, with the tests run before anyone reviews it.

Click through it at your own pace, or open it full screen.

The second demo sets up the local runner on your own machine, approves it with its device code, and then scans from the terminal. For a platform team working through an upgrade backlog, this is how you get a current, ranked inventory of a repository before deciding which open pull requests to merge, group or close.

Click through it at your own pace, or open it full screen.

Quick check

An open upgrade pull request fixes a KEV listed CVE but also moves a framework across a major version. What should you do?

Split it. Look for the smallest version change, ideally a backported patch on your current major, that resolves the KEV listed CVE and ship that first. Plan the major upgrade separately as a migration with an owner and a test plan.

You set the Vulnerabilities category to Balanced in Safeguard, but no pull requests appear on their own. Why?

Autonomous remediation ships switched off with every category at Manual. Strategy selections are saved but not applied until the master toggle is on. You can still open fix pull requests manually with AI Remediate in the meantime.

Sources

Last reviewed: 24 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.