Safeguard
Open Source Security

How Snyk's Fix PRs mechanically differ from Upgrade PRs a...

Snyk's Upgrade, Fix, and Backlog PRs aren't interchangeable — each changes different files and carries different CI risk. Here's the mechanical breakdown.

Priya Mehta
DevSecOps Engineer
8 min read

When Snyk finds a vulnerable dependency in a manifest file, it doesn't always respond the same way. Depending on whether a non-breaking fixed version exists upstream, whether Snyk maintains its own security patch for that specific CVE, and how a project's remediation settings are configured, Snyk will open one of three structurally different pull requests: an Upgrade PR that bumps a version string in package.json (or the ecosystem equivalent) and regenerates the lockfile, a Fix PR that can contain either a version bump or a source-level patch diff depending on which remediation path Snyk resolves to, or nothing at all in the short term — leaving the issue to sit in a project's vulnerability backlog until a scheduled, batched PR sweeps it up later. These aren't cosmetic naming differences. Each PR type touches different files, carries a different CI blast radius, and demands a different review posture from whoever has to click "merge." Here's what's actually happening under the hood.

What is a Snyk Upgrade PR, mechanically?

An Upgrade PR is a single, narrowly scoped diff that changes a version constraint in the manifest file and regenerates the corresponding lockfile — nothing else. If Snyk flags, say, lodash@4.17.15 for CVE-2020-8203 (prototype pollution), an Upgrade PR rewrites the dependency line to 4.17.21 in package.json, then runs the package manager's resolver so package-lock.json or yarn.lock reflects the new resolved tree. No application code is touched. Snyk's documented logic tries to pick the lowest version that clears the vulnerability while staying within the semver range your project already allows (or the "minimal upgrade" you've configured), rather than jumping straight to the newest major release, specifically to reduce the chance of a breaking change riding along with the security fix. For transitive dependencies, Snyk generates the upgrade path by walking up the dependency tree to find which direct dependency needs to be bumped to pull in the fixed transitive version, sometimes producing a diff to a parent package you didn't even know depended on the vulnerable one. The defining trait of an Upgrade PR is that it is entirely manifest-and-lockfile scoped — it either compiles and passes your tests or it doesn't, with no ambiguity about what changed.

How does a Fix PR differ from an Upgrade PR in what it actually changes?

A Fix PR is Snyk's broader remediation container, and it can contain either an upgrade diff or a patch diff — the label "Fix" describes the intent (resolve the vulnerability by whatever means is available), while "Upgrade" describes one specific mechanism (bump a version). When you click "Fix this vulnerability" in the Snyk UI or dashboard, or when auto-remediation is enabled on a project, Snyk resolves the best available action for that specific issue and opens a PR reflecting it. If a safe upgrade path exists, the resulting Fix PR is mechanically identical to an Upgrade PR — same manifest and lockfile changes. But if no fixed version has been published upstream and Snyk maintains a curated security patch for that vulnerability, the Fix PR instead ships a source-level diff against the files inside the installed package (typically under node_modules for npm projects) plus an entry in the project's .snyk policy file recording that the patch was applied and to which vulnerability ID it corresponds. That's the mechanical distinction worth internalizing: "Upgrade PR" always means a dependency-version change; "Fix PR" is the umbrella term, and its actual diff can be a version bump, a patch, or in some cases both bundled together when multiple issues on the same dependency get resolved in one pass.

When does Snyk apply a patch instead of an upgrade?

Snyk falls back to a patch only when no upstream release exists that clears the vulnerability without also forcing a version jump outside what your remediation policy allows. Patches are pre-built by Snyk's security research team for a subset of known vulnerabilities — they are not generated per-repository or per-customer, and they are not available for every CVE Snyk tracks. Because a patch modifies files inside the installed package rather than the manifest, it's inherently more fragile across time: if the vulnerable package publishes a new minor or patch release later (even an unrelated one), the byte-level diff Snyk's patch expects to apply cleanly can drift out of alignment with the new file contents, and the patch PR fails to apply or has to be regenerated. This is also why patch-based Fix PRs tend to be transitional by design — Snyk's own guidance frames patches as a stopgap that should be replaced by a real upgrade PR once a maintainer ships an actual fixed version, rather than a permanent remediation.

What is a backlog PR and why doesn't every vulnerability get fixed immediately?

A backlog PR is what results when a vulnerability can't be remediated the moment it's detected, so it's queued rather than shipped as an immediate one-off PR, and later gets addressed in a scheduled or grouped sweep. This happens for a few concrete reasons: no fixed version and no available patch exist yet (the issue sits open until upstream ships something); the project has "automatic Fix PRs" configured on a schedule (e.g., weekly) rather than real-time, so multiple accumulated issues on unrelated dependencies get evaluated together and opened as a batch of PRs, or grouped into a single PR depending on the project's PR-grouping setting; or the vulnerability count on a single dependency exceeds what the team wants surfaced as separate PRs, so Snyk consolidates them. Mechanically, a backlog-driven PR looks like several smaller Upgrade or Fix PRs merged into one diff — multiple manifest lines changed at once, a larger lockfile delta, and a commit message or PR description enumerating each CVE being closed rather than referencing a single one. The tradeoff is explicit: fewer PRs to review, but each one carries a wider blast radius if something in the batch breaks a build.

How do these three PR types differ in CI risk and review time?

They differ mainly in how much of the dependency tree moves per PR, which directly maps to how much can go wrong in one CI run. An Upgrade PR touches one dependency's version and its immediate resolution graph, so a failing test run is easy to attribute to a specific package bump. A patch-based Fix PR touches no version numbers at all — dependency resolution is untouched, so CI failures are almost never about compatibility, but the patch itself can silently fail to apply cleanly if the underlying package has drifted, in which case the PR simply won't contain the expected fix even though it looks merged and green. A backlog-driven batch PR carries the combined risk of every individual change it bundles — if five packages get bumped in one PR and CI fails, isolating which bump caused it requires reverting and bisecting rather than reading a single diff. This is the practical reason security teams often ask engineering to review Upgrade PRs quickly, patch-based Fix PRs with a note to re-verify the patch after any related dependency changes, and batch/backlog PRs with the same scrutiny you'd give a small dependency-update sprint rather than a single-line change.

How Safeguard Helps

Understanding which PR type you're looking at matters because it changes what you should actually verify before merging — a version bump, a patch diff, or a bundle of both. Safeguard gives teams a way to see that distinction directly instead of inferring it from a diff: our platform ingests remediation PRs from tools like Snyk, classifies whether the change is a manifest-only upgrade, a source-level patch, or a batched set of fixes, and correlates each one against your live SBOM and deployed artifact inventory so you know which services are actually exposed to the CVE being closed before you spend review time on it. For patch-based fixes specifically, Safeguard tracks whether the underlying package has since published a newer release upstream, flagging stale patches that should be replaced by a real upgrade rather than left in place indefinitely. And because backlog and batch PRs bundle multiple changes, Safeguard's provenance and dependency-graph checks help isolate exactly which component in a bundled PR introduces new transitive risk, so a wide-blast-radius PR doesn't get rubber-stamped just because it's inconvenient to unpack by hand. The goal isn't to replace the remediation engine doing the fixing — it's to give the humans approving those fixes the context to do it with actual confidence.

Never miss an update

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