Designing and being involved in the development of modern web applications, I've learned that security vulnerabilities can expose systems to serious risks, from data breaches to service disruptions. Whether I'm building with React on the frontend or .NET APIs on the backend, I've made it a habit to regularly scan for and address vulnerabilities as a critical part of my development workflow.
In this guide, I'll share the tools and processes I use daily for identifying and resolving security vulnerabilities in both my React and .NET applications. These are the actual practices I follow in my own projects.
Table of Contents
- How I Check Vulnerabilities in My React Applications
- How I Check Vulnerabilities in My .NET Solutions
- My Best Practices for Vulnerability Management
- How I Automate Security Scanning in CI/CD
- My Conclusions
Checking Vulnerabilities in React Applications
1. Using npm audit - My Go-To Tool
The most straightforward way I check for vulnerabilities in my React projects is using npm's built-in audit command. I run this almost daily on my frontend projects.
How I Run a Basic Vulnerability Scan
# I navigate to my React project directory
cd frontend
# Then I run npm audit
npm audit
When I run this command, it:
- Scans my
package.jsonandpackage-lock.json - Compares my dependencies against the npm vulnerability database
- Shows me a report with severity levels (low, moderate, high, critical)
Understanding What I See in the Output
βββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β High β Prototype Pollution in json-schema β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Package β json-schema β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Patched in β >=0.4.0 β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Dependency of β react-scripts β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Path β react-scripts > webpack > json-schema β
βββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
How I Automatically Fix Issues
# I let npm automatically fix vulnerabilities where possible
npm audit fix
# Sometimes I use force for major version updates (but I'm always careful!)
npm audit fix --force
β οΈ Warning from my experience: I've learned that npm audit fix --force can introduce breaking changes. I always test thoroughly after running this command - trust me, I've been burned by this before!
2. Using Yarn - My Alternative Approach
When I'm working on projects that use Yarn instead of npm, here's what I do:
# Check for vulnerabilities
yarn audit
# Interactive fix
yarn audit fix
In my experience, Yarn's audit output is sometimes clearer than npm's, especially when dealing with complex dependency trees.
3. Advanced Scanning with Snyk - My Favorite Tool
Snyk is what I use when I need a more comprehensive security analysis. I've integrated it into my projects and it's been a game-changer.
How I Installed Snyk
npm install -g snyk
How I Authenticate and Scan My Projects
# First, I authenticate with Snyk
snyk auth
# Then I test my project
snyk test
# I also set up continuous monitoring for my production apps
snyk monitor
Why I Love Snyk
- Detailed remediation advice: It gives me step-by-step guidance on fixing issues
- License compliance: It helps me check for licensing issues
- Docker scanning: I can scan my container images
- IDE integration: I get real-time vulnerability detection right in VS Code
4. Using OWASP Dependency-Check - For Comprehensive Analysis
When I need really comprehensive dependency analysis, I use this:
# Install dependency-check
npm install -g dependency-check
# Run scan
dependency-check --project "My React App" --scan ./frontend
From my experience, this tool is particularly useful when I'm preparing for security audits or need to generate detailed reports for compliance purposes.
5. How I Resolve React Vulnerabilities
My Strategy 1: Update Dependencies
This is usually my first approach:
# I update a specific package that has issues
npm update package-name
# Or I update all packages to their latest compatible versions
npm update
# I always check what's outdated first
npm outdated
My Strategy 2: Replace Vulnerable Packages
When a package has unresolved vulnerabilities, here's what I do:
- I search for alternatives:
npm search alternative-package - I check GitHub to see if it's actively maintained
- If I really need that specific package, I consider forking and patching it myself
In my experience, it's often better to find a well-maintained alternative than to stick with an abandoned package, even if it means refactoring some code.
My Strategy 3: Override Dependencies (My Last Resort)
When nothing else works, I use npm overrides in my package.json:
{
"overrides": {
"vulnerable-package": "^safe-version"
}
}
Checking Vulnerabilities in .NET Solutions
1. Using dotnet list package - My Primary .NET Tool
The .NET CLI includes built-in vulnerability scanning, and I use it extensively on my backend projects.
How I Check for Vulnerable Packages
# I navigate to my solution directory
cd backend
# Then I list packages with vulnerabilities
dotnet list package --vulnerable
# I also include transitive dependencies to catch everything
dotnet list package --vulnerable --include-transitive
What I See in My Output
Project `MyApi` has the following vulnerable packages
[net8.0]:
Top-level Package Requested Resolved Severity Advisory URL
> Newtonsoft.Json 12.0.1 12.0.1 High https://github.com/advisories/GHSA-5crp-9r3c-p9vr
2. How I Check for Outdated Packages
I regularly run these commands to stay on top of updates:
# I list outdated packages
dotnet list package --outdated
# I check for the highest patch, minor, and major versions
dotnet list package --outdated --highest-patch
dotnet list package --outdated --highest-minor
From what I've learned, staying on top of updates is much easier than dealing with a massive backlog of outdated packages later.
3. Using NuGet Package Manager in Visual Studio
When I'm working in Visual Studio, I also use the GUI:
- I right-click on the solution in Solution Explorer
- I select "Manage NuGet Packages for Solution..."
- I click the "Updates" tab
- I look for packages with a security warning icon π
4. Advanced Scanning with OWASP Dependency-Check for My .NET Projects
# Install dependency-check-cli
# Download from https://github.com/dependency-check/DependencyCheck
# Run scan
dependency-check.bat --project "My API" --scan ".\backend" --format HTML --out ".\reports"
In my experience, the HTML reports from this tool are excellent for sharing with non-technical stakeholders - they're detailed yet easy to understand.
5. How I Use Snyk for .NET
I also use Snyk for my .NET projects:
# I scan my .NET solution
snyk test --file=MySolution.sln
# And monitor it continuously
snyk monitor --file=MySolution.sln
6. How I Stay Updated with Microsoft's Security Advisories
I regularly check the official .NET Security GitHub repo: https://github.com/dotnet/announcements/issues
I've also subscribed to security announcements so I get notified immediately when something important comes up.
7. How I Resolve .NET Vulnerabilities
My Strategy 1: Update NuGet Packages
This is usually where I start:
# I update a specific package across all my projects
dotnet add package PackageName --version latest
# Or I update it in a specific project
cd .\backend\src\MyApi
dotnet add package PackageName --version latest
My Strategy 2: Update Transitive Dependencies
Sometimes vulnerabilities are in transitive dependencies. Here's what I do to force an update:
<!-- In my .csproj file, I add this -->
<ItemGroup>
<PackageReference Include="VulnerablePackage" Version="SafeVersion" />
</ItemGroup>
My Strategy 3: Use Central Package Management
I've started using Central Package Management in my projects. Here's how I set it up:
I create a Directory.Packages.props file in my solution root:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Serilog" Version="3.1.1" />
</ItemGroup>
</Project>
Then in my .csproj files, I don't specify versions anymore:
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Serilog" />
</ItemGroup>
Based on my experience, this approach has been a game-changer for managing package versions across multiple projects in my solution - one place to update, and all projects benefit.
My Strategy 4: Use .NET Security Policies
I configure vulnerability severity thresholds in my projects to fail builds when issues are found:
<PropertyGroup>
<NuGetAudit>true</NuGetAudit>
<NuGetAuditMode>direct</NuGetAuditMode>
<NuGetAuditLevel>low</NuGetAuditLevel>
</PropertyGroup>
This will cause my builds to fail if vulnerabilities are detected above the specified level. It's saved me several times!
Best Practices for Vulnerability Management
1. My Regular Scanning Schedule
I created a weekly scan script that I run every Monday morning. Here's what it looks like:
# Create a weekly scan script (PowerShell)
# scan-vulnerabilities.ps1
Write-Host "Scanning Frontend..." -ForegroundColor Cyan
cd frontend
npm audit
npm outdated
Write-Host "`nScanning Backend..." -ForegroundColor Cyan
cd ../backend
dotnet list package --vulnerable --include-transitive
dotnet list package --outdated
In my experience, having a consistent schedule makes security scanning a habit rather than an afterthought. I literally have this blocked on my calendar every Monday at 9 AM.
2. How I Handle Dependency Pinning vs. Range
I've learned to be strategic about version specifications:
For My Production Code:
{
"dependencies": {
"react": "19.0.0", // Exact version
"axios": "~1.6.0" // Patch updates only
}
}
For My Development Projects:
{
"dependencies": {
"react": "^19.0.0" // Minor updates allowed
}
}
From my experience, using exact versions in production has saved me from several "it works on my machine" scenarios. I learned this the hard way after a minor version update broke our production build.
3. My Security-First Dependency Selection Process
Before I add any new package to my projects, I always check:
- npm/NuGet download statistics: I prefer popular packages because they're usually better maintained
- GitHub activity: I look for recent commits - they indicate active maintenance
- Security history: I check if there have been past vulnerabilities and how quickly they were fixed
- License compatibility: I ensure it won't cause legal issues for my project
4. How I Implement Lockfiles
For My Frontend:
- I always commit
package-lock.jsonoryarn.lockto my repo - I use
npm ciin my CI/CD instead ofnpm installfor deterministic builds
For My Backend:
- I commit
packages.lock.jsonwhen using Central Package Management - I use deterministic restore:
dotnet restore --locked-mode
In my experience, lockfiles are non-negotiable. I once spent two hours debugging an issue that turned out to be caused by inconsistent dependency versions across team members' machines. Never again!
5. My Security Policies with Dependabot
I've set up Dependabot in my GitHub repo. Here's my .github/dependabot.yml:
version: 2
updates:
# Frontend dependencies
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
# Backend dependencies
- package-ecosystem: "nuget"
directory: "/backend"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
Automated CI/CD Integration
My GitHub Actions Setup
I've set up automated security scanning in my GitHub Actions. Here's the workflow I use for my projects:
Create .github/workflows/security-scan.yml:
name: Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
schedule:
# Run every Monday at 9 AM
- cron: '0 9 * * 1'
jobs:
frontend-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: |
cd frontend
npm ci
- name: Run npm audit
run: |
cd frontend
npm audit --audit-level=moderate
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
backend-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore dependencies
run: |
cd backend
dotnet restore
- name: Check for vulnerabilities
run: |
cd backend
dotnet list package --vulnerable --include-transitive
- name: Run Snyk
uses: snyk/actions/dotnet@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high --file=backend/MySolution.sln
From my experience, automating security scans in CI/CD catches issues before they reach production. I've caught several vulnerabilities in pull requests that would have otherwise slipped through.
My Azure DevOps Pipeline
When I work with Azure DevOps, here's the pipeline I use:
trigger:
branches:
include:
- main
- develop
stages:
- stage: SecurityScan
displayName: 'Security Vulnerability Scan'
jobs:
- job: FrontendScan
displayName: 'Frontend Security Scan'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
displayName: 'Install Node.js'
- script: |
cd frontend
npm ci
npm audit --audit-level=moderate
displayName: 'npm audit'
- job: BackendScan
displayName: 'Backend Security Scan'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
version: '8.0.x'
displayName: 'Install .NET SDK'
- script: |
cd backend
dotnet restore
dotnet list package --vulnerable --include-transitive
displayName: 'Check .NET vulnerabilities'
How I Handle False Positives
Sometimes vulnerability scanners report issues that don't actually affect my application. Here's how I deal with them:
For My npm/Yarn Projects
I create an .npmrc or add to my package.json:
{
"audit": {
"exclude": [
"GHSA-xxxx-xxxx-xxxx"
]
}
}
For My .NET Projects
I use NuGetAuditSuppress in my .csproj:
<PropertyGroup>
<NuGetAudit>true</NuGetAudit>
<NuGetAuditSuppress>CVE-2023-12345;CVE-2023-67890</NuGetAuditSuppress>
</PropertyGroup>
β οΈ Important: I always document why I'm suppressing each vulnerability. Future me (or my teammates) will thank me later!
What I've learned: only suppress vulnerabilities after thoroughly investigating them. I keep a SECURITY.md file in my repo documenting each suppression with the reasoning behind it.
My Emergency Response Workflow
When a critical vulnerability is discovered, here's exactly what I do:
1. I Assess Impact (Within 1 hour)
# I check if I'm actually using the vulnerable package
npm ls vulnerable-package
dotnet list package | findstr VulnerablePackage
2. I Take Immediate Action (Within 4 hours)
- I apply patches or updates right away
- If there's no patch available, I implement workarounds
- Sometimes I even temporarily disable affected features to protect my users
In my experience, it's better to temporarily take a feature offline than to leave a critical vulnerability exposed. I've done this twice, and users always understood when we explained the security risk.
3. I Deploy the Fix (Within 24 hours)
# Frontend
cd frontend
npm update vulnerable-package
npm audit
npm run build
npm test
# Backend
cd backend
dotnet add package VulnerablePackage --version SafeVersion
dotnet build --no-incremental
dotnet test
4. I Verify the Fix Works
# I verify no vulnerabilities remain in my project
npm audit
dotnet list package --vulnerable --include-transitive
5. I Do a Post-Incident Review
- I document what happened and what I learned
- I update my security policies based on lessons learned
- I improve my monitoring to catch similar issues faster next time
From what I've learned, every security incident is a learning opportunity. I keep a private incident log where I document what went wrong and how I fixed it - it's been invaluable for improving my processes.
Conclusion
Maintaining secure React and .NET applications requires ongoing vigilance and a systematic approach. Here's what I've learned from my experience building production applications:
My Key Takeaways
- Regular Scanning: I run vulnerability scans at least weekly - usually every Monday morning with my coffee
- Automated Monitoring: I use tools like Dependabot, Snyk, and GitHub Advanced Security so I don't miss anything
- Quick Response: I have a clear plan for addressing critical vulnerabilities fast
- Dependency Hygiene: I keep my dependencies up-to-date and minimize unnecessary packages
- CI/CD Integration: I've made security scanning part of my build pipeline so issues are caught early
My Recommended Tools Summary
| Tool | Best For | Cost |
|---|---|---|
| npm audit | Quick React scans | Free |
| dotnet list package | .NET vulnerability checks | Free |
| Snyk | Comprehensive scanning | Free tier available |
| GitHub Dependabot | Automated updates | Free with GitHub |
| OWASP Dependency-Check | Deep analysis | Free |
| WhiteSource/Mend | Enterprise solutions | Paid |
What I Recommend You Do Next
- Run your first vulnerability scan today - seriously, do it right now!
- Set up automated scanning in your CI/CD pipeline (it took me about 30 minutes)
- Create a security response plan for your team
- Schedule regular dependency updates in your calendar
- Subscribe to security advisories for your stack
From my experience: Security is not a one-time task but an ongoing process. By integrating these practices into your development workflow like I have, you'll significantly reduce your application's attack surface and be much better prepared when vulnerabilities are discovered.
I've been following these practices in my projects, and it's saved me from several potential security issues. The time investment is absolutely worth it!
Additional Resources That I Use
- npm Security Best Practices
- .NET Security Guidelines
- OWASP Top 10
- Snyk Documentation
- GitHub Security Advisories
- NuGet Package Vulnerabilities
Stay secure! π
P.S. - If you found this helpful, feel free to reach out with your own security practices. I'm always learning new ways to keep my applications safe!
π¬ Comments & Reactions