June 29, 2026
We Stopped Vulnerable Code from Reaching Production with Snyk. Here’s How
Security used to be something that happened at the end of our release cycle. Developers built features, QA tested them, and only before…

By Hari Prasad Nattuva
4 min read
Security used to be something that happened at the end of our release cycle. Developers built features, QA tested them, and only before production would security scans begin.
The problem?
Finding vulnerabilities late meant updating libraries, rebuilding Docker images, retesting the application, and often delaying releases.
We wanted security to become part of our everyday development process instead of a last-minute checkpoint.
To achieve this, we integrated Snyk into our Azure DevOps CI/CD pipeline to automatically scan our .NET applications, NuGet dependencies, Docker images, and continuously monitor deployed applications for newly discovered vulnerabilities.
The result was simple:
Developers fixed vulnerabilities during development — not after deployment.
In this article, I'll walk through our implementation, from installation to Azure DevOps integration, Docker image scanning, continuous monitoring, and the lessons we learned.
Our Security Pipeline
We redesigned our pipeline so security became another quality gate alongside unit testing.
Developer
│
Pull Request
│
Build
│
Unit Tests
│
Snyk Code Scan
│
Dependency Scan
│
Docker Build
│
Snyk Container Scan
│
Publish Image
│
Deploy to AKS
│
Continuous MonitoringDeveloper
│
Pull Request
│
Build
│
Unit Tests
│
Snyk Code Scan
│
Dependency Scan
│
Docker Build
│
Snyk Container Scan
│
Publish Image
│
Deploy to AKS
│
Continuous MonitoringInstead of waiting until production, every Pull Request was automatically validated.
Even after deployment, Snyk continued monitoring the application for newly disclosed vulnerabilities.
Why We Selected Snyk
Our requirements were straightforward.
We wanted one platform capable of scanning:
- .NET source code
- NuGet dependencies
- Docker images
- Open Source vulnerabilities
- Known CVEs
- Container operating systems
We also wanted:
- Azure DevOps integration
- Automatic build failures
- Developer-friendly remediation guidance
- Continuous monitoring after deployment
Snyk met all of those requirements with minimal pipeline changes.
Step 1 — Create a Snyk Account
Create an organization in Snyk.
Generate an API Token from:
Account Settings
↓
API TokenAccount Settings
↓
API TokenThis token will later be used by Azure DevOps.
Step 2 — Install the Azure DevOps Extension
Open Azure DevOps Marketplace.
Search for:
Snyk Security Scan
Install the extension into your Azure DevOps organization.
The extension provides ready-to-use pipeline tasks for both application and container scanning.
Step 3 — Configure the Service Connection
Navigate to:
Project Settings
↓
Service Connections
↓
New Service ConnectionProject Settings
↓
Service Connections
↓
New Service ConnectionSelect Snyk Authentication.
Paste your API Token and give the connection a meaningful name such as:
Snyk-EnterpriseSnyk-EnterpriseYour pipelines can now authenticate securely.
Step 4 — Scan .NET Code and Dependencies
Once the application builds successfully, run the Snyk scan.
- task: SnykSecurityScan@1
displayName: "Snyk Code Scan"
inputs:
serviceConnectionEndpoint: 'Snyk-Enterprise'
testType: 'app'
monitorWhen: 'always'
failOnIssues: true
severityThreshold: 'high'- task: SnykSecurityScan@1
displayName: "Snyk Code Scan"
inputs:
serviceConnectionEndpoint: 'Snyk-Enterprise'
testType: 'app'
monitorWhen: 'always'
failOnIssues: true
severityThreshold: 'high'This performs:
- Static code analysis
- NuGet dependency scanning
- Open Source vulnerability detection
- CVE identification
If a High or Critical vulnerability is detected, the build stops automatically.
Step 5 — Build the Docker Image
Next we build our container image. You can do this via dotnet publish as well.
- task: Docker@2
inputs:
repository: company/api
command: build
Dockerfile: Dockerfile- task: Docker@2
inputs:
repository: company/api
command: build
Dockerfile: DockerfileAlthough the application code may be secure, the Docker image itself still needs validation.
Step 6 — Scan the Docker Image
After the Docker build completes, we immediately scan the container.
- task: SnykSecurityScan@1
displayName: "Container Scan"
inputs:
serviceConnectionEndpoint: 'Snyk-Enterprise'
testType: 'container'
dockerImageName: 'company/api:$(Build.BuildId)'
monitorWhen: 'always'
failOnIssues: true
severityThreshold: 'high'- task: SnykSecurityScan@1
displayName: "Container Scan"
inputs:
serviceConnectionEndpoint: 'Snyk-Enterprise'
testType: 'container'
dockerImageName: 'company/api:$(Build.BuildId)'
monitorWhen: 'always'
failOnIssues: true
severityThreshold: 'high'This identifies vulnerabilities in:
- Base images
- Linux packages
- OpenSSL
- Operating system libraries
- Container dependencies
One surprising discovery was that many vulnerabilities weren't introduced by our developers — they originated from outdated base images.
Updating the base image eliminated dozens of vulnerabilities without changing a single line of application code.
Step 7 — Enable Continuous Monitoring
This became one of the most valuable parts of our setup.
Imagine you deploy an application today.
Everything passes.
No vulnerabilities are reported.
Two weeks later, a new Critical CVE is published affecting one of your NuGet packages or Docker base image.
Your application hasn't changed.
Your pipeline doesn't run.
Without continuous monitoring, you may never know your production application has become vulnerable.
To solve this, we enabled Snyk monitoring.
monitorWhen: alwaysmonitorWhen: alwaysEach successful pipeline uploads a snapshot of the application's dependencies and container image to Snyk.
From that point onward, Snyk continuously compares those snapshots against newly published vulnerability databases.
Whenever a new CVE is disclosed, Snyk alerts the team — even if no new deployment has occurred.
This transformed security from a one-time build activity into an ongoing process.
Instead of discovering vulnerabilities during annual security reviews, we addressed them as part of normal sprint work.
Step 8 — Managing Exceptions
Not every reported vulnerability requires an immediate fix.
Some are:
- False positives
- Already mitigated
- Accepted business risks
- Awaiting vendor patches
Instead of disabling scans, we used a .snyk policy file to document approved exceptions.
ignore:
SNYK-DOTNET-123456:
- '*':
reason: Internal mitigation applied
expires: 2027-01-31ignore:
SNYK-DOTNET-123456:
- '*':
reason: Internal mitigation applied
expires: 2027-01-31Adding an expiry date ensured these exceptions were reviewed periodically instead of becoming permanent.
Step 9 — Build Quality Gates
Our release policy was intentionally simple.
SeverityPipeline ActionCriticalFail BuildHighFail BuildMediumWarningLowReport Only
Initially we only blocked High and Critical issues.
As development teams became comfortable with the process, we gradually addressed Medium severity findings as part of regular sprint planning.
Benefits We Observed
Integrating Snyk delivered several benefits.
Earlier Detection
Developers fixed vulnerabilities while they were actively working on the feature.
Faster Releases
Security validation became part of CI instead of delaying production deployments.
Better Dependency Hygiene
Outdated NuGet packages were upgraded regularly because vulnerabilities became visible immediately.
Secure Container Images
Many risks were eliminated simply by keeping Docker base images current.
Continuous Protection
New vulnerabilities discovered weeks or months after deployment were automatically detected.
Instead of waiting for the next release cycle, we scheduled fixes during normal development.
Improved Security Awareness
Developers received actionable remediation guidance directly within their Pull Requests and pipeline results.
Over time, secure coding became part of the team's everyday mindset rather than a separate security exercise.
Lessons Learned
Looking back, a few practices made the rollout successful.
- Start with reporting before enforcing build failures.
- Focus on High and Critical vulnerabilities first.
- Scan every Pull Request.
- Always scan container images — not just application code.
- Keep Docker base images updated regularly.
- Enable continuous monitoring after deployment.
- Review ignored vulnerabilities regularly.
- Treat vulnerability remediation like any other product backlog item.
Security works best when it becomes part of normal software development instead of a last-minute approval process.
Final Thoughts
Adding Snyk to our Azure DevOps pipeline did much more than automate security scans.
It changed when and how we addressed vulnerabilities.
Instead of reacting to security issues just before production, developers received immediate feedback while building features. Source code, third-party dependencies, and Docker images were validated automatically on every build. More importantly, continuous monitoring ensured that newly disclosed vulnerabilities were identified even after applications had been deployed.
For us, shifting security left wasn't just about introducing another tool — it was about making security a continuous part of the software delivery lifecycle.
When security becomes part of every Pull Request, every build, and every deployed application, fixing vulnerabilities becomes routine instead of reactive. That's where the real value of integrating Snyk into a modern .NET CI/CD pipeline lies.