NuGet restores the lowest version that satisfies all constraints, so a dependency declared as 1.0 or higher resolves to 1.0, not the newest release. This makes builds predictable, but it also means an old version with a known flaw can stay in your graph until you raise it.
The rule, in plain terms
Microsoft's dependency resolution documentation describes four rules for PackageReference projects: lowest applicable version, floating versions, direct dependency wins, and cousin dependencies. The first one matters most for security.
A plain version number such as 6.1 means "6.1 or higher", and NuGet resolves to the smallest acceptable stable version. It does not hunt for the newest.
Examples from the docs
| Declared | Meaning | Result |
|---|---|---|
| Version 6.1 | 6.1 or above | Lowest acceptable stable version |
Version 6.* | Any 6.x | Highest matching stable (floating) |
| Exact 6.1.0 in square brackets | Exactly 6.1.0 | 6.1.0 |
If the requested minimum is not on the feed, NuGet picks the next lowest version it can find, so a request for 2.1 or higher may resolve to 2.2.
Why this is good for repeatability
Because the answer does not drift upward each time a new release appears, builds are stable. The same inputs give the same graph, unless a lower matching version is published later. Microsoft notes that case too: publishing version 4.0.0 after you declared 4.0.0 or higher can change what resolves, because the exact match now exists.
Why it can leave you exposed
Package authors often declare a loose lower bound for compatibility. If package A says it needs B at 1.0 or higher, you get B 1.0, even if 1.0 has an advisory. Nothing upgrades it for you.
Two other rules affect what you can do:
- Direct dependency wins. If you reference B yourself, your version is used for that subgraph. This lets an application override a transitive version, and NuGet warns on a downgrade.
- Cousin dependencies. When different parts of the graph ask for different versions, NuGet picks the lowest version that satisfies all of them.
What to do about it
- Run an audit with transitive checking on, so low bounds do not hide advisories.
- Raise the closest package to a version whose own dependency range excludes the bad version.
- If that does not help, add a direct reference or use central package management with transitive pinning.
- Use a lock file so the result stays fixed once you have fixed it.
- Remove temporary direct references when the parent package catches up.
Try it yourself
Click through it at your own pace, or open it full screen. Find a transitive package and note which parent brought it in.
Safeguard's dependency scanning shows resolved versions across the graph, and a free scan lists any with known advisories.
Quick check
Will NuGet automatically upgrade a transitive package to the newest release?
No. It uses the lowest version that satisfies all constraints unless you reference or pin something higher.
What happens if I reference a transitive package directly at a lower version?
NuGet honors your direct reference and raises a downgrade warning, so do not go lower than your dependencies ask for.
Sources
- NuGet package dependency resolution, Microsoft Learn
- NuGet package version reference, Microsoft Learn
- NuGet PackageReference in project files, Microsoft Learn
Last reviewed: 19 October 2026.