Your NuGet packages are a bigger attack surface than your code.
Think about it: when was the last time you audited a dependency before running dotnet add package? You check the download count, maybe the GitHub stars, and move on. Meanwhile, you're trusting not just that package author, but every transitive dependency, every maintainer with commit access, and every build system that touched the release.
The 2021 SolarWinds breach wasn't a sophisticated zero-day exploit. It was a compromised build pipeline that injected malicious code into a trusted package. Eighteen thousand organizations installed it without question because it came from a source they trusted.
This is the supply chain security problem. And most teams are still solving it the wrong way.
How Teams Handle This Today (And Why It's Not Working)
Walk into any development shop and ask about their dependency security strategy. You'll hear about Dependabot, Snyk, or OWASP Dependency-Check running in CI/CD. They scan your .csproj files, match versions against CVE databases, and file tickets when they find something.
Great. Except these tools only catch known vulnerabilities after someone's already been exploited and reported it. That typosquatted package you installed last week? The one with a name one character off from a popular library? It won't show up in any CVE database because it's not a vulnerability—it's just malicious. Dependency scanners wave it right through.
Some teams try manual auditing. Before approving a package, someone checks the maintainer's reputation, looks at recent commits, verifies the download count isn't suspiciously low. This works great until you realize the average .NET application has over a hundred transitive dependencies. Manual review becomes a bottleneck, developers start copying packages directly to bypass approval, and your security posture gets worse instead of better.
Private NuGet feeds solve a different problem. You mirror approved packages to Azure Artifacts or MyGet, giving you control over what enters your ecosystem. Except now someone has to maintain that mirror, vet new packages before adding them, and somehow keep track of which mirrored versions have accumulated CVEs since you copied them over. It's just manual auditing with extra infrastructure.
Lock files at least prevent surprise updates. Your packages.lock.json ensures builds pull the exact same versions every time. But lock files don't prevent you from adding a compromised package in the first place—they just ensure you'll keep deploying it consistently.
Notice the pattern? Every traditional approach is reactive. They catch problems after packages are already in your dependency graph, your lock files, your build artifacts.
What's Missing: Install-Time Blocking
The gap in every approach above is timing. Scanners find vulnerabilities during CI/CD builds or scheduled scans—hours or days after developers install packages. By then, compromised dependencies are already in your codebase, your lock files, and potentially your build artifacts.
What you actually need is something that intercepts package requests before they reach developer machines. Block threats during dotnet restore, not after merge.
That's a fundamentally different architecture. Instead of scanning what's already installed, you need a security layer sitting between your package manager and the public registry that validates packages in real-time as they're requested.
The Visibility Problem Nobody Talks About
Even if you get blocking right, there's another problem: you probably don't know what packages your organization actually uses.
Not what's declared in .csproj files. Not what's supposed to be in production. What developers are actually pulling in real-time, across every project, every team, every environment.
Without centralized visibility, you're flying blind. You'll discover risky dependencies during incident response instead of proactively. You won't know which teams are using abandoned packages, which contractors are violating license requirements, or why three different projects are using three different JSON libraries.
Visibility transforms security from a gate-keeping function into a partnership. When you can see patterns as they emerge, you can reach out proactively: "Hey, noticed you're using this legacy HTTP client—we've got a supported alternative that's faster and more secure."
How ShieldedStack Solves This
ShieldedStack is a centrally managed HTTP proxy that sits between your developers and package registries (NuGet, npm, PyPI, Maven). It intercepts every package request, validates it against vulnerability databases and policy rules, and blocks threats before they reach your environment.
Setup is deliberate simple. Update your nuget.config to point at ShieldedStack's endpoint instead of nuget.org OR run it as centralized network infrastructure (if you organization can handle this), That's it. No CI/CD changes, no build script modifications, no new steps in developer workflows. Every dotnet restore now flows through install-time blocking automatically.
ShieldedStack runs in two modes depending on how much friction your team can tolerate:
Trust-Then-Verify mode lets packages through immediately while scanning in the background. Fast-moving teams get zero workflow disruption. The proxy still raises alerts if vulnerabilities are discovered post-download, but developers aren't blocked. This is visibility-first—you're building a complete picture of what your organization uses before you start enforcing hard blocks. This is also a great starting point, get the baseline, then flip the switch to Verify-Then-Trust.
Verify-Then-Trust mode blocks packages until they pass validation. ShieldedStack queries vulnerability databases inline for every package version, even unknown ones. Nothing gets through without clearance. This is zero-trust at the dependency level—stricter, but it guarantees malicious packages never reach developer machines or CI pipelines.
Most teams start with TrustThenVerify to build baseline visibility, then progressively tighten to VerifyThenTrust for critical projects or production pipelines.
Policy enforcement is centralized across your entire organization. One console controls security rules for npm, NuGet, PyPI, and Maven. Local developers, CI pipelines, and runtime restores all hit the same enforcement layer. No per-project configuration sprawl, no policy drift between environments.
You get complete visibility: every package request, who's using what, where blocks are happening, and what developers did when something got flagged. ShieldedStack tracks first patched versions, provides ecosystem-specific upgrade guidance, detects license changes, and generates risk-based reports so security teams can prioritize remediation based on more than CVE severity alone.
Performance is non-negotiable. Safe packages are cached aggressively so repeated requests are instant. The proxy doesn't slow down development—it just filters out the threats.
Start Here
If you're still relying on Dependabot to catch CVEs three months after they're exploited, you're playing defense. Supply chain attacks aren't slowing down—they're accelerating because they work. Developers trust packages. Automation pulls dependencies without question. A single compromised maintainer account can affect thousands of downstream applications.
You can't manually audit your way out of this. You need intelligent, automated prevention that works at the speed developers expect.
Get visibility into what your team is actually using. Define policies that match your risk tolerance. Shift security left so threats get blocked during package resolution, not discovered in production.
And stop treating supply chain security as a nice-to-have. It's not. It's infrastructure.
Want to see install-time blocking in action? Check out ShieldedStack or grab a trial to try it out for 30 days. Real-time threat detection for NuGet, npm, PyPI, and Maven.