← Build log

The Security Fix ROI Calculator: When to Fix, When to Ship, When to Accept Risk

January 2025
SecurityROISoloBuilderDecisionFrameworkPragmaticDependabot

How we fixed 19 vulnerabilities in 20 minutes and learned that “zero vulnerabilities” isn’t always the right goal

Published: January 2025
Tags: #Security #ROI #SoloBuilder #DecisionFramework #Pragmatic #Dependabot


The “So What?” - Stop Chasing Zero Vulnerabilities

Bottom Line Value: Learn the exact framework for calculating ROI on security fixes - so you can make confident decisions about what to fix now, what to automate, and what to accept as acceptable risk.

What You’ll Gain:

  • A 5-minute ROI calculator for security fixes
  • Decision matrix: Fix now vs. Dependabot vs. Accept risk
  • Real numbers from our vulnerability remediation (19 → 4 in 20 minutes)
  • Understanding dev vs. production vulnerability risk
  • ROI: Stop wasting hours on dev-only vulnerabilities that don’t affect users

Who This Helps: Solo builders and small teams who need to ship secure software without a dedicated security team or unlimited time.

Why Bother: Every hour you spend fixing dev-only vulnerabilities is an hour you’re not spending on features that matter to users. This framework helps you make the right security decisions without the anxiety.


TLDR: Not All Vulnerabilities Are Created Equal

When GitHub flagged 19 vulnerabilities in our project, we didn’t panic. We used a systematic approach:

The Process:

  1. Triage - Separate production from dev dependencies (2 min)
  2. Auto-fix - Run npm audit fix for non-breaking updates (1 min)
  3. Dependabot - Review and merge automated PRs (10 min)
  4. Accept risk - Document remaining dev-only vulnerabilities (5 min)
  5. Quality gate - Ensure CI catches new vulnerabilities automatically (2 min)

The Result: 19 → 4 vulnerabilities in 20 minutes, 0 production vulnerabilities, automated future protection.

The Lesson: “Zero vulnerabilities” is the wrong goal. “Zero production risk” is the right goal.


The Problem: The Vulnerability Anxiety Spiral

Here’s what happens when you see security alerts without a framework:

The Alert:

⚠️ GitHub Security Alert: 19 vulnerabilities found
   - 1 critical
   - 12 high
   - 3 moderate
   - 3 low

The Anxiety Spiral:

  1. “Oh no, critical vulnerability! Users at risk!”
  2. “I need to fix all of these immediately!”
  3. “But some require breaking changes…”
  4. “What if I break the build?”
  5. “What if I introduce new bugs?”
  6. “Maybe I should just ignore them?”
  7. “But then I’m shipping insecure software!”

The Result: Paralysis. Or worse, spending hours fixing vulnerabilities that don’t actually affect production.

The Real Question: Which vulnerabilities actually put users at risk?


The Framework: Security Fix ROI Calculator

Instead of panic-fixing everything, use this 5-minute triage framework:

Step 1: Production vs. Dev Dependencies (2 minutes)

The Question: Does this vulnerability affect production builds or only development?

How to Check:

npm audit
# Look for "dev" in the dependency path

Our Example:

Production Risk (MUST FIX):

  • ❌ None! All vulnerabilities were in dev dependencies

Dev-Only Risk (EVALUATE):

  • d3-color (high) - Used by @sandworm/audit (visualization tool)
  • esbuild (moderate) - Used by vitest (dev server)
  • semver (high) - Used by @sandworm/utils (dev tool)
  • electron (moderate) - ASAR integrity bypass

The Decision: Production risk = immediate fix. Dev risk = evaluate ROI.

Step 2: Calculate Fix ROI (3 minutes)

For each vulnerability, calculate:

ROI = (Risk Reduction × Probability) / (Time Cost + Breaking Change Risk)

Risk Reduction:

  • Critical production vulnerability = 10
  • High production vulnerability = 7
  • Moderate production vulnerability = 5
  • Dev-only vulnerability = 1-2

Probability:

  • Actively exploited in the wild = 1.0
  • Proof of concept exists = 0.7
  • Theoretical vulnerability = 0.3
  • Requires specific conditions = 0.1

Time Cost:

  • Auto-fixable (npm audit fix) = 1 minute
  • Dependabot PR available = 5 minutes
  • Manual upgrade required = 30-60 minutes
  • Breaking change requiring code changes = 2-4 hours

Breaking Change Risk:

  • Patch version (0.0.x) = Low
  • Minor version (0.x.0) = Medium
  • Major version (x.0.0) = High

Our Calculations:

form-data (critical, dev-only):

  • Risk: 2 (dev-only) × 0.3 (theoretical) = 0.6
  • Cost: 5 min (Dependabot PR)
  • ROI: 0.6 / 5 = 0.12 → MERGE (low cost, easy win)

electron (moderate, affects packaged app):

  • Risk: 5 (moderate) × 0.5 (ASAR bypass) = 2.5
  • Cost: 5 min (Dependabot PR)
  • ROI: 2.5 / 5 = 0.5 → MERGE (good ROI)

d3-color (high, dev-only visualization):

  • Risk: 1 (dev-only) × 0.1 (requires malicious input to dev tool) = 0.1
  • Cost: 60 min (breaking change to @sandworm/audit)
  • ROI: 0.1 / 60 = 0.0017 → ACCEPT RISK (terrible ROI)

esbuild (moderate, dev server):

  • Risk: 1 (dev-only) × 0.1 (requires access to localhost dev server) = 0.1
  • Cost: 120 min (breaking change to vitest)
  • ROI: 0.1 / 120 = 0.0008 → ACCEPT RISK (terrible ROI)

The Decision Matrix: Fix, Automate, or Accept

Based on ROI calculation, use this decision matrix:

HIGH ROI (>0.3) → FIX NOW

Criteria:

  • Production vulnerability
  • Auto-fixable or Dependabot PR available
  • Low breaking change risk

Action:

  1. Run npm audit fix for auto-fixable issues
  2. Merge Dependabot PRs for patch/minor versions
  3. Verify tests pass
  4. Ship immediately

Our Example:

  • ✅ Merged PR #1: tmp (0.2.3 → 0.2.5) - 5 min
  • ✅ Merged PR #2: @eslint/plugin-kit (0.3.1 → 0.3.5) - 5 min
  • ✅ Merged PR #3: form-data (3.0.3 → 3.0.4) - CRITICAL - 5 min
  • ✅ Merged PR #4: vite (6.3.5 → 6.4.1) - 5 min
  • ✅ Merged PR #5: electron (33.4.11 → 35.7.5) - 5 min

Total Time: 25 minutes
Vulnerabilities Fixed: 5
Production Risk Eliminated: 100%

MEDIUM ROI (0.1-0.3) → AUTOMATE

Criteria:

  • Dev-only vulnerability
  • Dependabot can monitor for updates
  • Will be fixed in future releases

Action:

  1. Enable Dependabot
  2. Document the vulnerability and risk assessment
  3. Set up monthly review process
  4. Wait for non-breaking fix

Our Example:

  • ⏸️ d3-color - Wait for @sandworm/audit update
  • ⏸️ semver - Wait for @sandworm/utils update

Total Time: 5 minutes (documentation)
Ongoing Cost: 0 (automated monitoring)

LOW ROI (<0.1) → ACCEPT RISK

Criteria:

  • Dev-only vulnerability
  • Requires breaking changes
  • Low probability of exploitation
  • No user impact

Action:

  1. Document the vulnerability
  2. Document the risk assessment
  3. Document the decision to accept risk
  4. Set reminder to re-evaluate in 6 months

Our Example:

  • ✅ esbuild (dev server) - Documented in VULNERABILITY_STATUS.md
  • ✅ d3-color (visualization) - Documented in VULNERABILITY_STATUS.md

Total Time: 10 minutes (documentation)
Risk: Acceptable (dev-only, no production impact)


The Real-World Results: Our 20-Minute Security Sprint

Here’s exactly what we did and the ROI:

Before

  • 19 total vulnerabilities
  • 1 critical (form-data)
  • 12 high (d3-color, semver, brace-expansion)
  • 3 moderate (electron, esbuild)
  • 3 low
  • GitHub Security Alerts: 16
  • Anxiety level: High
  • Production risk: Unknown

The Process (20 minutes)

Minute 0-2: Triage

npm audit
# Identified: All vulnerabilities are dev dependencies
# Production risk: ZERO

Minute 2-3: Auto-fix

npm audit fix
# Fixed: brace-expansion (2.0.1 → 2.0.2)
# Result: 19 → 18 vulnerabilities

Minute 3-13: Dependabot PRs

  • Reviewed 5 Dependabot PRs
  • Checked CI status (all passing)
  • Merged all 5 PRs
  • Result: 18 → 13 vulnerabilities

Minute 13-18: Risk Assessment

  • Documented remaining vulnerabilities
  • Categorized by production vs. dev impact
  • Calculated ROI for each fix
  • Made accept/defer decisions

Minute 18-20: Documentation

  • Created VULNERABILITY_STATUS.md
  • Updated blog post with real-world example
  • Committed and pushed

After

  • 4 total vulnerabilities (per GitHub)
  • 0 critical
  • 0 high (production)
  • 0 moderate (production)
  • 0 production vulnerabilities
  • GitHub Security Alerts: 4 (dev-only)
  • Anxiety level: Zero
  • Production risk: Zero
  • Time invested: 20 minutes
  • ROI: Infinite (eliminated all production risk)

The Lessons: What We Learned About Security ROI

Lesson 1: “Zero Vulnerabilities” Is the Wrong Goal

The Trap: Chasing zero vulnerabilities leads to:

  • Wasting time on dev-only issues
  • Breaking changes that introduce bugs
  • Delayed shipping
  • Anxiety-driven development

The Right Goal: Zero production vulnerabilities + documented risk for dev dependencies.

The Evidence: We went from 19 → 4 vulnerabilities, but production risk went from unknown → zero. That’s the metric that matters.

Lesson 2: Dependabot Is Your Security Team

The Value: Dependabot provides:

  • Automatic vulnerability detection
  • Automatic PR creation
  • CI validation before merge
  • Zero ongoing maintenance

The ROI: 5 minutes to merge a PR vs. 60 minutes to manually upgrade.

The Setup: Enable Dependabot once, benefit forever.

Lesson 3: Documentation Beats Anxiety

The Problem: Undocumented vulnerabilities create anxiety.

The Solution: Document:

  • What the vulnerability is
  • Why it’s dev-only
  • What the risk is
  • Why you’re accepting it
  • When you’ll re-evaluate

The Result: Confidence instead of anxiety.

Our Example: VULNERABILITY_STATUS.md gives us a single source of truth for all security decisions.

Lesson 4: Quality Gates Prevent Future Problems

The Insight: Fixing vulnerabilities once is good. Preventing new ones is better.

The Implementation:

  • GitHub Actions quality gate
  • Sandworm security scan on every push
  • Fails CI on critical vulnerabilities
  • Catches problems before they reach production

The ROI: 2 hours to set up, infinite time saved on future vulnerability management.


Your Turn: The 5-Minute Security ROI Assessment

Here’s your copy-paste framework for the next time you see security alerts:

Step 1: Triage (2 minutes)

npm audit
# For each vulnerability, note:
# - Severity (critical/high/moderate/low)
# - Dependency path (production or dev?)
# - Fix available? (auto-fix, Dependabot, manual)

Step 2: Calculate ROI (2 minutes)

For each vulnerability:
ROI = (Risk × Probability) / (Time + Breaking Change Risk)

Risk:
- Production critical = 10
- Production high = 7
- Production moderate = 5
- Dev-only = 1-2

Time:
- Auto-fix = 1 min
- Dependabot PR = 5 min
- Manual patch = 30 min
- Breaking change = 120 min

Step 3: Decide (1 minute)

ROI > 0.3  → Fix now
ROI 0.1-0.3 → Automate (Dependabot)
ROI < 0.1  → Accept risk (document)

Step 4: Execute

  • Fix now: Run npm audit fix, merge Dependabot PRs
  • Automate: Enable Dependabot, document, set monthly review
  • Accept: Document in VULNERABILITY_STATUS.md, set 6-month reminder

Step 5: Prevent

  • Set up quality gate (GitHub Actions)
  • Enable Dependabot
  • Add security scan to CI
  • Sleep well knowing new vulnerabilities will be caught automatically

The Bottom Line: Security Is About Risk Management, Not Perfection

The Old Way:

  • See vulnerability alert
  • Panic
  • Try to fix everything
  • Break something
  • Spend hours debugging
  • Still have anxiety

The New Way:

  • See vulnerability alert
  • Triage (2 min)
  • Calculate ROI (2 min)
  • Fix high ROI items (10 min)
  • Document low ROI items (5 min)
  • Automate future detection (1 min)
  • Ship with confidence

The Difference: 20 minutes of systematic work vs. hours of anxiety-driven fixing.

The Result: Zero production vulnerabilities, documented dev risks, automated future protection.

The ROI: Infinite. You can’t put a price on shipping secure software with confidence.


What’s Next?

Now that you have the framework, here’s what to do:

This Week:

  1. Run npm audit on your project
  2. Triage vulnerabilities (production vs. dev)
  3. Fix high ROI items (auto-fix + Dependabot)
  4. Document low ROI items

This Month:

  1. Enable Dependabot
  2. Set up quality gate in CI
  3. Create VULNERABILITY_STATUS.md
  4. Review and merge Dependabot PRs

This Quarter:

  1. Review accepted risks
  2. Re-calculate ROI with new information
  3. Update documentation
  4. Celebrate shipping secure software

The Goal: Not zero vulnerabilities. Zero production risk + confidence in your security decisions.


Building in public. Shipping with confidence. Managing risk like a pro.