# Vulnerability Report

> Scans project dependencies for known vulnerabilities (CVEs), categorizes them into three severity-based reports (Critical/High, Medium, Low), and generates detailed markdown documents with remediation guidance. Saves output to project-decisions/ folder. Use when the user says "vulnerability report", "dependency vulnerabilities", "CVE report", "package vulnerabilities", "npm audit report", "dependency scan", "vulnerable packages", "security vulnerabilities in dependencies", or "generate vulnerability reports".

- Skill: `aakash-dhar/vulnerability-report` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aakash-dhar/vulnerability-report`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aakash-dhar/vulnerability-report/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: aakash-dhar (https://skillmd.com/u/aakash-dhar)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/aakash-dhar/vulnerability-report

---


# Vulnerability Report Skill

When generating vulnerability reports, scan all project dependencies for known CVEs, categorize findings by severity, and produce three separate reports — one for each severity tier. Each report is a standalone document with full context, remediation steps, and priority guidance.

**IMPORTANT**: Always save THREE markdown files to the `project-decisions/` directory:
1. `YYYY-MM-DD-vulnerabilities-high.md` — Critical and High severity (CVSS ≥ 7.0)
2. `YYYY-MM-DD-vulnerabilities-medium.md` — Medium severity (CVSS 4.0–6.9)
3. `YYYY-MM-DD-vulnerabilities-low.md` — Low and Informational (CVSS < 4.0)

## 0. Output Setup
````bash
mkdir -p project-decisions

# Files will be saved as:
# project-decisions/YYYY-MM-DD-vulnerabilities-high.md
# project-decisions/YYYY-MM-DD-vulnerabilities-medium.md
# project-decisions/YYYY-MM-DD-vulnerabilities-low.md
````

## 1. Dependency Discovery

### Detect Package Ecosystem
````bash
# Detect all package managers in use
echo "=== Package Ecosystems Detected ==="

# Node.js / JavaScript / TypeScript
ls package.json package-lock.json yarn.lock pnpm-lock.yaml bun.lockb 2>/dev/null && echo "→ Node.js detected"

# Python
ls requirements.txt Pipfile pyproject.toml poetry.lock setup.py setup.cfg 2>/dev/null && echo "→ Python detected"

# Go
ls go.mod go.sum 2>/dev/null && echo "→ Go detected"

# Ruby
ls Gemfile Gemfile.lock 2>/dev/null && echo "→ Ruby detected"

# PHP
ls composer.json composer.lock 2>/dev/null && echo "→ PHP detected"

# Rust
ls Cargo.toml Cargo.lock 2>/dev/null && echo "→ Rust detected"

# Java
ls pom.xml build.gradle build.gradle.kts 2>/dev/null && echo "→ Java detected"

# .NET
ls *.csproj *.sln packages.config 2>/dev/null && echo "→ .NET detected"

# Docker (base image vulnerabilities)
ls Dockerfile Dockerfile.* docker-compose.yml 2>/dev/null && echo "→ Docker detected"
````

### Inventory Dependencies
````bash
# Node.js — count direct and transitive
echo "=== Node.js Dependencies ==="
echo "Direct dependencies: $(cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('dependencies',{})))" 2>/dev/null || echo "N/A")"
echo "Dev dependencies: $(cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('devDependencies',{})))" 2>/dev/null || echo "N/A")"
echo "Total installed: $(ls node_modules/ 2>/dev/null | wc -l || echo "N/A")"

# Python
echo "=== Python Dependencies ==="
pip list --format=columns 2>/dev/null | wc -l || echo "N/A"
cat requirements.txt 2>/dev/null | grep -v "^#\|^$" | wc -l || echo "N/A"

# Go
echo "=== Go Dependencies ==="
cat go.sum 2>/dev/null | awk '{print $1}' | sort -u | wc -l || echo "N/A"

# Ruby
echo "=== Ruby Dependencies ==="
cat Gemfile.lock 2>/dev/null | grep "    [a-z]" | wc -l || echo "N/A"

# PHP
echo "=== PHP Dependencies ==="
cat composer.lock 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('packages',[])))" 2>/dev/null || echo "N/A"
````

## 2. Vulnerability Scanning

### Node.js / npm
````bash
# Full npm audit with JSON output
npm audit --json 2>/dev/null > /tmp/npm-audit-output.json

# Parse audit results
cat /tmp/npm-audit-output.json | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    
    # npm v7+ format
    if 'vulnerabilities' in data:
        vulns = data['vulnerabilities']
        for name, info in sorted(vulns.items(), key=lambda x: {'critical':0,'high':1,'moderate':2,'low':3,'info':4}.get(x[1].get('severity','info'), 5)):
            severity = info.get('severity', 'unknown')
            via = info.get('via', [])
            fix = info.get('fixAvailable', False)
            range_affected = info.get('range', 'unknown')
            
            # Get CVE details from via
            cves = []
            if isinstance(via, list):
                for v in via:
                    if isinstance(v, dict):
                        cves.append({
                            'title': v.get('title', 'N/A'),
                            'url': v.get('url', ''),
                            'severity': v.get('severity', severity),
                            'cwe': v.get('cwe', []),
                            'cvss': v.get('cvss', {}).get('score', 'N/A'),
                            'range': v.get('range', range_affected)
                        })
            
            print(f'PACKAGE: {name}')
            print(f'  Severity: {severity.upper()}')
            print(f'  Affected: {range_affected}')
            print(f'  Fix Available: {fix}')
            for cve in cves:
                print(f'  CVE Title: {cve[\"title\"]}')
                print(f'  CVSS Score: {cve[\"cvss\"]}')
                print(f'  URL: {cve[\"url\"]}')
                print(f'  CWE: {cve[\"cwe\"]}')
            print()
    
    # Summary
    metadata = data.get('metadata', {}).get('vulnerabilities', {})
    print('=== SUMMARY ===')
    print(f'Critical: {metadata.get(\"critical\", 0)}')
    print(f'High: {metadata.get(\"high\", 0)}')
    print(f'Moderate: {metadata.get(\"moderate\", 0)}')
    print(f'Low: {metadata.get(\"low\", 0)}')
    print(f'Info: {metadata.get(\"info\", 0)}')
    print(f'Total: {metadata.get(\"total\", 0)}')
except Exception as e:
    print(f'Error parsing: {e}', file=sys.stderr)
" 2>/dev/null

# Also check with npm audit fix --dry-run to see what's auto-fixable
npm audit fix --dry-run 2>/dev/null | tail -20
````

### Node.js / yarn
````bash
# Yarn audit
yarn audit --json 2>/dev/null | head -100
````

### Node.js / pnpm
````bash
# pnpm audit
pnpm audit --json 2>/dev/null | head -100
````

### Python / pip
````bash
# pip-audit (preferred)
pip install pip-audit --break-system-packages 2>/dev/null
pip-audit --format=json 2>/dev/null > /tmp/pip-audit-output.json
cat /tmp/pip-audit-output.json | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    for vuln in data:
        name = vuln.get('name', 'unknown')
        version = vuln.get('version', 'unknown')
        vulns = vuln.get('vulns', [])
        for v in vulns:
            print(f'PACKAGE: {name}=={version}')
            print(f'  ID: {v.get(\"id\", \"N/A\")}')
            print(f'  Fix Versions: {v.get(\"fix_versions\", [])}')
            print(f'  Description: {v.get(\"description\", \"N/A\")[:200]}')
            print()
except Exception as e:
    print(f'Error: {e}', file=sys.stderr)
" 2>/dev/null

# Safety check (alternative)
pip install safety --break-system-packages 2>/dev/null
safety check --json 2>/dev/null | head -100
````

### Go
````bash
# govulncheck
go install golang.org/x/vuln/cmd/govulncheck@latest 2>/dev/null
govulncheck ./... 2>/dev/null
````

### Ruby
````bash
# bundler-audit
gem install bundler-audit 2>/dev/null
bundle-audit check --update 2>/dev/null
````

### PHP
````bash
# Composer audit
composer audit --format=json 2>/dev/null | head -100
````

### Docker Base Images
````bash
# Check Dockerfile base images
echo "=== Docker Base Images ==="
grep "^FROM" Dockerfile Dockerfile.* 2>/dev/null

# Check if base images are pinned
grep "^FROM" Dockerfile 2>/dev/null | while read line; do
  image=$(echo "$line" | awk '{print $2}')
  echo "$image" | grep -q ":" || echo "⚠️ UNPINNED: $image (using :latest implicitly)"
  echo "$image" | grep -q ":latest" && echo "⚠️ UNPINNED: $image (using :latest explicitly)"
  echo "$image" | grep -qE ":[0-9]" && echo "✅ PINNED: $image"
  echo "$image" | grep -qE "@sha256:" && echo "✅ DIGEST PINNED: $image"
done
````

### Lockfile Integrity
````bash
# Check lockfiles exist and are committed
echo "=== Lockfile Status ==="
for lockfile in package-lock.json yarn.lock pnpm-lock.yaml Pipfile.lock poetry.lock Gemfile.lock composer.lock Cargo.lock go.sum; do
  if [ -f "$lockfile" ]; then
    if git ls-files --error-unmatch "$lockfile" >/dev/null 2>&1; then
      echo "✅ $lockfile — committed"
    else
      echo "⚠️ $lockfile — exists but NOT committed to git"
    fi
  fi
done

# Check for unpinned versions in package.json
echo ""
echo "=== Unpinned Versions ==="
cat package.json 2>/dev/null | python3 -c "
import sys, json
data = json.load(sys.stdin)
for section in ['dependencies', 'devDependencies']:
    deps = data.get(section, {})
    for name, version in deps.items():
        if version.startswith('^') or version.startswith('~') or version == '*' or version == 'latest':
            print(f'  {section}/{name}: {version}')
" 2>/dev/null
````

## 3. Vulnerability Classification

### Severity Mapping

Map each finding to a consistent severity:

| Source | Critical | High | Medium | Low |
|--------|----------|------|--------|-----|
| **npm audit** | critical | high | moderate | low |
| **pip-audit/safety** | CVSS ≥ 9.0 | CVSS 7.0-8.9 | CVSS 4.0-6.9 | CVSS < 4.0 |
| **bundler-audit** | critical | high | medium | low |
| **govulncheck** | Map from CVSS | Map from CVSS | Map from CVSS | Map from CVSS |
| **Composer** | critical | high | medium | low |
| **CVSS v3.1** | 9.0-10.0 | 7.0-8.9 | 4.0-6.9 | 0.1-3.9 |

### Enrichment Per Vulnerability

For each vulnerability found, gather:
````
- Package name and installed version
- Vulnerability ID (CVE, GHSA, OSV)
- CVSS score and vector
- CWE classification
- Severity (Critical/High/Medium/Low)
- Description of the vulnerability
- Affected version range
- Fixed version (if available)
- Is it a direct or transitive dependency?
- Is the vulnerable code reachable from our code?
- Exploit availability (PoC exists? actively exploited?)
- Fix available? (auto-fixable with npm audit fix?)
- Remediation steps
````

### Reachability Analysis
````bash
# Check if vulnerable package is directly imported (higher risk)
# vs only a transitive dependency (lower risk)
for pkg in [list-of-vulnerable-packages]; do
  echo "=== $pkg ==="
  
  # Direct dependency?
  cat package.json 2>/dev/null | grep "\"$pkg\"" && echo "  → DIRECT dependency"
  
  # Imported in source code?
  grep -rn "import.*$pkg\|require.*$pkg\|from '$pkg'\|from \"$pkg\"" --include="*.ts" --include="*.js" --include="*.py" src/ app/ 2>/dev/null && echo "  → DIRECTLY USED in source code"
  
  # Only transitive?
  npm ls "$pkg" 2>/dev/null | head -5
done
````

## 4. Report Generation

Generate THREE separate reports, one for each severity tier:

### Report 1: Critical & High Vulnerabilities

**File:** `project-decisions/YYYY-MM-DD-vulnerabilities-high.md`

**Audience:** Security team, engineering leads, management — requires immediate action
````markdown
# 🔴 Vulnerability Report: Critical & High Severity

**Project:** [Project Name]
**Scan Date:** YYYY-MM-DD
**Scanned By:** [Name / Automated]
**Ecosystems Scanned:** [npm, pip, Go, Ruby, PHP, Docker]
**Action Required:** 🔴 IMMEDIATE — Fix within 48 hours

---

## Executive Summary

| Metric | Value |
|--------|-------|
| **Critical vulnerabilities** | X |
| **High vulnerabilities** | X |
| **Total in this report** | X |
| **Auto-fixable** | X (Y%) |
| **Requires manual fix** | X (Y%) |
| **No fix available** | X (Y%) |
| **Direct dependencies affected** | X |
| **Transitive dependencies affected** | X |

### Risk Assessment

**Overall Risk: [🔴 Critical / 🟠 High]**

[2-3 sentences: what's the worst case if these aren't fixed? 
Are any actively exploited? Is sensitive data at risk?]

---

## Quick Fix Commands

Run these immediately to fix auto-fixable vulnerabilities:
```bash
# Node.js — auto-fix what's possible
npm audit fix

# If breaking changes are acceptable
npm audit fix --force

# Python — upgrade to fixed versions
pip install --upgrade [package1] [package2] --break-system-packages

# Ruby
bundle update [gem1] [gem2]

# PHP
composer update [package1] [package2]
```

**After running fixes, re-scan:**
```bash
npm audit
pip-audit
```

---

## Detailed Findings

### VULN-001: [Package Name] — [Vulnerability Title]

| Field | Value |
|-------|-------|
| **Package** | `[package-name]` |
| **Installed Version** | `X.Y.Z` |
| **Severity** | 🔴 Critical |
| **CVSS Score** | X.X |
| **CVSS Vector** | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| **CVE** | [CVE-YYYY-XXXXX](https://nvd.nist.gov/vuln/detail/CVE-YYYY-XXXXX) |
| **CWE** | [CWE-XXX](https://cwe.mitre.org/data/definitions/XXX.html) — [Name] |
| **GHSA** | [GHSA-xxxx-xxxx-xxxx](https://github.com/advisories/GHSA-xxxx-xxxx-xxxx) |
| **Dependency Type** | Direct / Transitive |
| **Reachable** | Yes — imported in `src/services/auth.ts` / No — transitive only |
| **Exploit Available** | Yes — PoC published / No known exploit |
| **Actively Exploited** | Yes — in the wild / No |
| **Affected Versions** | `>= X.Y.Z, < A.B.C` |
| **Fixed Version** | `A.B.C` |
| **Fix Available** | ✅ Yes — upgrade to `A.B.C` / ❌ No fix yet |
| **Auto-Fixable** | ✅ `npm audit fix` / ❌ Manual intervention required |

**Description:**
[What the vulnerability allows an attacker to do.
How it could be exploited in the context of THIS project.]

**Impact on This Project:**
[Specific to YOUR codebase — is the vulnerable function actually called? 
Is the attack vector reachable? What data is at risk?]

**Dependency Chain:**
````
your-project
  └── [direct-dependency]@X.Y.Z
       └── [vulnerable-package]@A.B.C  ← VULNERABLE

