In March 2023, researchers at JFrog pulled back the curtain on a NuGet typosquatting campaign that had already been running for weeks. Thirteen malicious packages — including Coinbase.Core, Anarchy.Wrapper.Net, and DiscordRichPresence.API — mimicked the names of popular libraries closely enough that developers copy-pasted install commands without a second glance. Before JFrog and ReversingLabs got them pulled on March 21, 2023, the three most popular alone had been downloaded more than 166,000 times, quietly dropping a custom crypto stealer dubbed "Impala Stealer" onto developer machines. That single campaign captures the core problem with the NuGet ecosystem: package names are cheap, trust is assumed by default, and a single mistyped dotnet add package command can hand an attacker code execution inside a developer's machine or a CI/CD pipeline. Typosquatting is only half the story — dependency confusion is the other, and together they've made .NET one of the more active fronts in software supply chain security.
What Is NuGet Typosquatting?
NuGet typosquatting is the practice of publishing a package under a name that looks or reads almost identically to a popular, legitimate one, betting that a developer will mistype a command, skim a search result, or trust a familiar-looking icon and install the wrong thing. Because NuGet's package namespace is flat and case-insensitive, and because anyone can register almost any unclaimed ID for free, the barrier to entry is close to zero — an attacker just needs a name that's visually or phonetically close enough to survive a glance.
The March 2023 campaign is a textbook example. DiscordRichPresence.API was built to be confused with the legitimate, widely used DiscordRichPresence library; a developer scanning search results or copying a snippet from an old Stack Overflow answer had no obvious reason to look twice. Coinbase.Core borrowed brand recognition from Coinbase's developer tooling to look official. None of the three needed a security flaw in NuGet itself — they exploited human pattern-matching, not code. Microsoft's response has been the package ID prefix reservation program, which lets verified owners lock down a namespace prefix (like Microsoft.* or System.*) and displays a badge on nuget.org and in Visual Studio when a package comes from a verified owner of that prefix. It helps for well-known brands that bother to reserve their prefixes, but it does nothing for the long tail of smaller open-source libraries that typosquatters actually target.
How Does Dotnet Dependency Confusion Exploit Feed Priority?
Dotnet dependency confusion doesn't rely on a misleading name at all — it relies on how NuGet decides which feed to trust when a package name exists in more than one place. Most .NET projects pull packages from multiple sources: the public nuget.org gallery plus one or more private or internal feeds for proprietary libraries. When a build tool is configured to check both and simply picks the highest version number it finds, an attacker who learns the name of an internal package (from a leaked .csproj file, a public GitHub repo, or an error message) can publish a public package with the same name and an artificially high version number. The build resolves to the attacker's package instead of the internal one — no phishing, no exploit, no user interaction required.
This technique was popularized in February 2021 when researcher Alex Birsan published research showing he could achieve confirmed code execution inside Microsoft, Apple, PayPal, Shopify, Netflix, Uber, and more than 30 other companies, ultimately earning over $130,000 in bug bounties. While his highest-profile proofs of concept targeted npm and Python, the same resolution logic applies to NuGet: it checks multiple configured package sources and, absent explicit pinning, can prefer whichever feed offers the newer version. The NuGet team has acknowledged the risk directly — GitHub issue #10566 on the NuGet/Home repository, titled "Preventing the Dependency Confusion attack," has tracked community requests for stronger default protections like scoped feed mapping ever since. Today, packageSourceMapping in NuGet.Config lets teams explicitly bind package ID patterns to specific feeds, but it's opt-in — projects that never configure it remain exposed by default.
What Do Real Malicious NuGet Package Campaigns Look Like?
Real malicious NuGet package campaigns tend to follow a pattern: typosquatted names, an automatically executed install script, and a payload that phones home. The March 2023 Impala Stealer campaign used exactly that shape — an init.ps1 PowerShell script bundled inside each package ran automatically the moment dotnet restore pulled it down, downloading a second-stage Windows executable that targeted the Exodus cryptocurrency wallet and exfiltrated credentials.
Attackers kept iterating. In October 2023, a separate campaign distributed a NuGet package that dropped the SeroXen remote access trojan, giving attackers persistent remote control over infected developer machines. And starting around August 2023, ReversingLabs tracked a longer-running campaign it named "IAmReboot," in which attackers moved away from install-time PowerShell scripts entirely and began hiding malicious code inside .targets and .props files — the MSBuild integration files that NuGet packages can ship to hook into a project's build process. By July 2024, researchers had uncovered another 60 malicious packages in a related wave, this time using IL weaving to splice obfuscated downloader code directly into otherwise-legitimate compiled binaries, making static inspection far less useful. Each wave got quieter and harder to spot than the last.
Why Does NuGet's Build-Time Execution Make These Attacks More Dangerous?
NuGet's build-time execution model is more dangerous than a typical install script because it hands attacker code a foothold inside the build itself, not just the developer's local machine. MSBuild integrations — a feature that has existed since NuGet 2.5 to let packages hook into compilation via .targets and .props files — support inline tasks that can contain arbitrary executable code. That code runs every time the project is built, not just once at install, and it runs with whatever access the build process has: source code, environment variables, cloud credentials, signing keys, and CI/CD secrets.
That's a meaningfully worse blast radius than an init.ps1 popping a single workstation. A poisoned package sitting quietly in a packages.lock.json file can re-execute on every pipeline run, on every developer's machine that restores the project, and inside every downstream build that consumes an artifact produced by the compromised pipeline. It's also why the shift researchers observed — from install scripts to MSBuild inline tasks to IL-woven binaries — matters: each step moved the payload further from where developers instinctively look (a package's top-level files) and deeper into places that automated tooling and manual review both tend to skip.
How Can Teams Detect a NuGet Supply Chain Attack Before It Ships?
Teams catch a NuGet supply chain attack before it ships by combining strict dependency hygiene with active scanning, because neither alone is sufficient. That starts with packages.lock.json and pinned exact versions instead of floating ranges, so a compromised package can't silently ride in on an automatic minor-version bump. It continues with packageSourceMapping in NuGet.Config, which explicitly ties package ID prefixes to specific feeds and closes the exact resolution ambiguity that dependency confusion depends on. Checking for the reserved-prefix badge on nuget.org before adopting an unfamiliar package, verifying publisher identity and package signing, and being suspicious of libraries with sparse commit history but suspiciously high download counts all help catch typosquats before they reach a .csproj file.
None of that catches everything, though — the whole point of campaigns like IAmReboot was to blend in with legitimate-looking build tooling. That's why mature teams pair policy with continuous, automated scanning of every dependency that enters a build: static analysis of install scripts and MSBuild targets, behavioral detection for packages that make unexpected network calls or spawn processes, and diffing package contents against their published source to catch tampering. Treating open-source dependencies with the same scrutiny as first-party code, rather than as an inert list of names and version numbers, is what closes the gap between "we have a policy" and "we actually caught it."
How Safeguard Helps
Safeguard is built for exactly this gap. Instead of trusting a package because its name looks right and its version number is high, Safeguard continuously analyzes the actual contents and behavior of every NuGet, npm, PyPI, and other open-source dependency entering your pipelines — flagging typosquatted names, unexpected install-time or build-time scripts, and MSBuild inline tasks that don't match a package's stated purpose before they ever reach a production build.
Safeguard also closes the dependency confusion gap directly: it maps your internal and private package namespaces, verifies that build configurations resolve names to the sources you actually intend, and alerts when a public package appears that could shadow an internal one. Paired with software bill of materials tracking and provenance verification across your full dependency tree, Safeguard gives .NET teams the visibility to catch a malicious NuGet package the moment it's introduced — not months later, after it's been silently rebuilt into every downstream artifact your organization ships.