dependency-vulnerability-triage
Turns npm audit/Snyk results into prioritized patch plans with severity assessment, safe upgrade paths, breaking change analysis, and rollback strategies. Use for "dependency security", "vulnerability patching", "npm audit", or "security updates".
$ Installieren
git clone https://github.com/patricio0312rev/skillset /tmp/skillset && cp -r /tmp/skillset/templates/security/dependency-vulnerability-triage ~/.claude/skills/skillset// tip: Run this command in your terminal to install the skill
SKILL.md
name: dependency-vulnerability-triage description: Turns npm audit/Snyk results into prioritized patch plans with severity assessment, safe upgrade paths, breaking change analysis, and rollback strategies. Use for "dependency security", "vulnerability patching", "npm audit", or "security updates".
Dependency Vulnerability Triage
Convert vulnerability reports into actionable patch plans.
Vulnerability Severity Matrix
// severity-matrix.ts
export interface Vulnerability {
id: string;
package: string;
currentVersion: string;
patchedVersion: string;
severity: "critical" | "high" | "medium" | "low";
cvss: number;
cwe: string[];
exploitability: "high" | "medium" | "low";
impact: string;
path: string[];
}
export interface PatchPriority {
vulnerability: Vulnerability;
priority: 1 | 2 | 3 | 4;
reasoning: string;
patchWindow: "24h" | "1week" | "1month" | "next-release";
breakingChange: boolean;
testingRequired: "minimal" | "moderate" | "extensive";
}
export function calculatePriority(vuln: Vulnerability): PatchPriority {
let priority: 1 | 2 | 3 | 4 = 4;
let patchWindow: "24h" | "1week" | "1month" | "next-release" = "next-release";
let testingRequired: "minimal" | "moderate" | "extensive" = "minimal";
// P1: Critical + High Exploitability + Production
if (
vuln.severity === "critical" &&
vuln.exploitability === "high" &&
isProductionDependency(vuln.package)
) {
priority = 1;
patchWindow = "24h";
testingRequired = "moderate";
}
// P2: High + Medium/High Exploitability
else if (
vuln.severity === "high" &&
["high", "medium"].includes(vuln.exploitability)
) {
priority = 2;
patchWindow = "1week";
testingRequired = "moderate";
}
// P3: Medium or Low Exploitability High
else if (
vuln.severity === "medium" ||
(vuln.severity === "high" && vuln.exploitability === "low")
) {
priority = 3;
patchWindow = "1month";
testingRequired = "minimal";
}
return {
vulnerability: vuln,
priority,
reasoning: `${vuln.severity} severity, ${vuln.exploitability} exploitability`,
patchWindow,
breakingChange: isBreakingChange(vuln.currentVersion, vuln.patchedVersion),
testingRequired,
};
}
Audit Report Parser
// scripts/parse-audit.ts
import { execSync } from "child_process";
interface NpmAuditResult {
vulnerabilities: Record<string, any>;
metadata: {
vulnerabilities: {
critical: number;
high: number;
moderate: number;
low: number;
};
};
}
function parseNpmAudit(): Vulnerability[] {
const auditOutput = execSync("npm audit --json", { encoding: "utf-8" });
const audit: NpmAuditResult = JSON.parse(auditOutput);
const vulnerabilities: Vulnerability[] = [];
Object.entries(audit.vulnerabilities).forEach(([pkg, data]) => {
vulnerabilities.push({
id: data.via[0]?.url || `vuln-${pkg}`,
package: pkg,
currentVersion: data.range,
patchedVersion: data.fixAvailable?.version || "N/A",
severity: data.severity,
cvss: data.via[0]?.cvss?.score || 0,
cwe: data.via[0]?.cwe || [],
exploitability: determineExploitability(data),
impact: data.via[0]?.title || "Unknown",
path: data.via.map((v: any) => v.name),
});
});
return vulnerabilities;
}
function determineExploitability(data: any): "high" | "medium" | "low" {
// Check if actively exploited
if (
data.via[0]?.findings?.some((f: any) => f.exploit === "proof-of-concept")
) {
return "high";
}
// Check CVSS exploitability subscore
const exploitScore = data.via[0]?.cvss?.exploitabilityScore;
if (exploitScore > 3.5) return "high";
if (exploitScore > 2.0) return "medium";
return "low";
}
Patch Plan Generator
// scripts/generate-patch-plan.ts
interface PatchPlan {
immediate: PatchPriority[]; // P1 - 24h
shortTerm: PatchPriority[]; // P2 - 1 week
mediumTerm: PatchPriority[]; // P3 - 1 month
longTerm: PatchPriority[]; // P4 - next release
breakingChanges: PatchPriority[];
safeUpgrades: PatchPriority[];
}
function generatePatchPlan(vulnerabilities: Vulnerability[]): PatchPlan {
const prioritized = vulnerabilities.map(calculatePriority);
return {
immediate: prioritized.filter((p) => p.priority === 1),
shortTerm: prioritized.filter((p) => p.priority === 2),
mediumTerm: prioritized.filter((p) => p.priority === 3),
longTerm: prioritized.filter((p) => p.priority === 4),
breakingChanges: prioritized.filter((p) => p.breakingChange),
safeUpgrades: prioritized.filter((p) => !p.breakingChange),
};
}
function printPatchPlan(plan: PatchPlan) {
console.log("# Security Patch Plan\n");
console.log("## 🚨 Immediate (24 hours)\n");
plan.immediate.forEach((p) => {
console.log(
`- **${p.vulnerability.package}** ${p.vulnerability.currentVersion} → ${p.vulnerability.patchedVersion}`
);
console.log(` ${p.vulnerability.impact}`);
console.log(` Breaking: ${p.breakingChange ? "YES ⚠️" : "No"}`);
});
console.log("\n## ⚡ Short-term (1 week)\n");
plan.shortTerm.forEach((p) => {
console.log(
`- **${p.vulnerability.package}** ${p.vulnerability.currentVersion} → ${p.vulnerability.patchedVersion}`
);
});
console.log("\n## 📅 Medium-term (1 month)\n");
plan.mediumTerm.forEach((p) => {
console.log(
`- ${p.vulnerability.package} ${p.vulnerability.currentVersion} → ${p.vulnerability.patchedVersion}`
);
});
console.log("\n## ⚠️ Breaking Changes\n");
plan.breakingChanges.forEach((p) => {
console.log(`- ${p.vulnerability.package}: Review migration guide`);
});
}
Safe Upgrade Order
// Dependency graph-based upgrade order
interface DependencyGraph {
[pkg: string]: string[];
}
function determineSafeUpgradeOrder(
patches: PatchPriority[]
): PatchPriority[][] {
const graph = buildDependencyGraph();
const ordered: PatchPriority[][] = [];
// Level 0: No dependencies on other patches
const level0 = patches.filter(
(p) => !hasUpgradeDependencies(p.vulnerability.package, patches, graph)
);
ordered.push(level0);
// Level 1+: Depends on previous levels
let remaining = patches.filter((p) => !level0.includes(p));
let level = 1;
while (remaining.length > 0 && level < 10) {
const currentLevel = remaining.filter((p) =>
canUpgradeNow(p.vulnerability.package, ordered.flat(), graph)
);
if (currentLevel.length === 0) break; // Circular dependency
ordered.push(currentLevel);
remaining = remaining.filter((p) => !currentLevel.includes(p));
level++;
}
return ordered;
}
// Example output:
// Level 0: [lodash, axios] - No dependencies
// Level 1: [express] - Depends on lodash
// Level 2: [next] - Depends on express
Risk Assessment
interface RiskAssessment {
package: string;
riskFactors: string[];
riskScore: number; // 1-10
mitigations: string[];
}
function assessUpgradeRisk(patch: PatchPriority): RiskAssessment {
const risks: string[] = [];
let score = 0;
// Check for breaking changes
if (patch.breakingChange) {
risks.push("Breaking changes detected");
score += 4;
}
// Check for major version bump
if (
isMajorVersionBump(
patch.vulnerability.currentVersion,
patch.vulnerability.patchedVersion
)
) {
risks.push("Major version upgrade");
score += 3;
}
// Check usage patterns
const usage = analyzePackageUsage(patch.vulnerability.package);
if (usage.importCount > 50) {
risks.push("Heavily used in codebase");
score += 2;
}
// Check test coverage
if (usage.testCoverage < 0.7) {
risks.push("Low test coverage");
score += 2;
}
return {
package: patch.vulnerability.package,
riskFactors: risks,
riskScore: Math.min(score, 10),
mitigations: generateMitigations(risks),
};
}
function generateMitigations(risks: string[]): string[] {
const mitigations: string[] = [];
if (risks.includes("Breaking changes detected")) {
mitigations.push("Read CHANGELOG and migration guide");
mitigations.push("Test on feature branch first");
mitigations.push("Deploy to staging before production");
}
if (risks.includes("Heavily used in codebase")) {
mitigations.push("Run full test suite");
mitigations.push("Perform manual smoke tests");
mitigations.push("Monitor error rates after deploy");
}
if (risks.includes("Low test coverage")) {
mitigations.push("Add tests for critical paths");
mitigations.push("Extend monitoring");
}
return mitigations;
}
Automated Patch Script
#!/bin/bash
# scripts/apply-patches.sh
set -e
PRIORITY=$1 # immediate, short-term, medium-term
if [ -z "$PRIORITY" ]; then
echo "Usage: ./apply-patches.sh [immediate|short-term|medium-term]"
exit 1
fi
echo "🔧 Applying $PRIORITY patches..."
# Generate patch plan
npm audit --json > audit-report.json
node scripts/generate-patch-plan.js --priority=$PRIORITY > patch-plan.json
# Apply patches
while IFS= read -r package; do
echo "Updating $package..."
# Try to apply fix
npm audit fix --package-lock-only --package=$package
# Run tests
if npm test; then
echo "✅ Tests passed for $package"
git add package.json package-lock.json
git commit -m "security: patch $package vulnerability"
else
echo "❌ Tests failed for $package - reverting"
git checkout package.json package-lock.json
fi
done < <(jq -r '.packages[]' patch-plan.json)
echo "✅ Patches applied"
CI Vulnerability Gating
# .github/workflows/security-audit.yml
name: Security Audit
on:
pull_request:
schedule:
- cron: "0 0 * * *" # Daily
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=moderate
continue-on-error: true
- name: Run Snyk test
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
- name: Generate patch plan
if: failure()
run: npm run generate-patch-plan
- name: Comment PR
if: failure() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const plan = fs.readFileSync('patch-plan.md', 'utf8');
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: plan
});
Patch Rollback Strategy
## Vulnerability Patch Rollback Plan
### Before Patching
1. **Create rollback tag**
```bash
git tag -a pre-security-patch-$(date +%Y%m%d) -m "Pre-patch checkpoint"
```
-
Document current versions
npm list --depth=0 > versions-before.txt -
Run baseline tests
npm test > test-results-before.txt
Rollback Steps
If issues detected after patching:
-
Immediate revert
git revert HEAD git push origin main -
Redeploy previous version
git checkout pre-security-patch-$(date +%Y%m%d) npm ci npm run build npm run deploy -
Verify rollback
npm test npm run smoke-tests -
Incident report
- Document what failed
- Update patch plan with new risk factors
- Schedule retry with additional testing
## Best Practices
1. **Triage weekly**: Review new vulnerabilities
2. **Prioritize by impact**: Not just severity score
3. **Test before merging**: Automated + manual testing
4. **Stage deployments**: Dev → Staging → Production
5. **Monitor after patch**: Watch error rates
6. **Document breaking changes**: Migration guides
7. **Keep dependencies updated**: Reduce vulnerability surface
## Output Checklist
- [ ] Severity matrix defined
- [ ] Audit parser implemented
- [ ] Patch plan generated
- [ ] Safe upgrade order determined
- [ ] Risk assessment completed
- [ ] Breaking changes identified
- [ ] Automated patch script
- [ ] CI vulnerability gating
- [ ] Rollback strategy documented
- [ ] Team notified of critical patches
Repository

patricio0312rev
Author
patricio0312rev/skillset/templates/security/dependency-vulnerability-triage
2
Stars
0
Forks
Updated3d ago
Added1w ago