Cve reachability analyzer
Skill yigityildiz0/universal-ai-skill-library/skills/common/cve-reachability-analyzer
531 searchable AI Agent Skills for Claude Code, OpenAI Codex, and OpenCode — EN/TR catalog, platform and risk notes, direct ZIPs, and curated bundles.
npx -y skills add yigityildiz0/universal-ai-skill-library --skill cve-reachability-analyzerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 18 days oldThe repository was created 18 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Determine whether a CVE in a dependency actually affects your application by tracing call paths from your code to vulnerable functions, analyzing transitive.
SKILL.md
21.2 KB, as published. Nobody here has run it
CVE Reachability Analyzer
Trace the execution path from your application code through direct and transitive dependencies to determine whether a reported CVE in a dependency is actually reachable and exploitable in your specific context. This skill dramatically reduces the noise from dependency scanners by distinguishing between vulnerabilities that exist in your dependency tree and vulnerabilities that your application can actually trigger.
When to Use This Skill
Use this skill when you need to:
- Determine if a CVE flagged in
npm audit,pip-audit,trivy, or similar tools actually affects your application - Triage a large backlog of dependency vulnerability findings
- Justify deferring a dependency upgrade that would require significant refactoring
- Build evidence for risk acceptance decisions about specific CVEs
- Reduce false-positive rates from automated security scanners
- Understand how deeply a vulnerable function is embedded in your dependency chain
- Assess the impact of a newly disclosed zero-day in a popular library
- Prioritize which dependency upgrades deliver actual security value
- Validate that a dependency upgrade actually removes the vulnerable code path
Trigger phrases: "is this CVE reachable", "dependency vulnerability analysis", "call graph analysis", "transitive dependency check", "false positive check", "reachability analysis", "vulnerable function tracing", "dependency call path"
What This Skill Does
Core Capabilities
- Dependency Tree Construction: Build a complete graph of direct and transitive dependencies
- Vulnerable Function Identification: Pinpoint the exact function, method, or class that contains the vulnerability
- Call Graph Tracing: Trace from application entry points through dependency layers to the vulnerable function
- Transitive Dependency Analysis: Follow the chain through multiple levels of indirection
- Import Analysis: Determine which modules and functions are actually imported and used
- False Positive Classification: Categorize unreachable CVEs with supporting evidence
- Reachability Reporting: Generate clear reports with call chains and evidence
Reachability Classification
| Classification | Definition | Action |
|---|---|---|
| Directly Reachable | Application code calls the vulnerable function | Fix immediately |
| Indirectly Reachable | A used dependency calls the vulnerable function | Fix based on severity |
| Conditionally Reachable | Reachable only under specific configuration or input | Evaluate conditions |
| Phantom Dependency | Dependency is declared but never imported | Remove or ignore |
| Unreachable | No execution path from application to vulnerable function | Document and defer |
Analysis Methodology
CVE Report Input
|
v
Step 1: Identify Vulnerable Function
|
v
Step 2: Build Dependency Graph
|
v
Step 3: Analyze Imports and Usage
|
v
Step 4: Trace Call Paths
|
v
Step 5: Evaluate Conditions
|
v
Step 6: Classify and Report
Instructions
Phase 1: Identify the Vulnerable Function
Every CVE affects a specific function, method, class, or code path within the dependency. Before analyzing reachability, pinpoint exactly what is vulnerable.
Step 1.1: Gather CVE details
# Fetch CVE details from the NVD API
curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2024-29041" | \
jq '{
id: .vulnerabilities[0].cve.id,
description: .vulnerabilities[0].cve.descriptions[0].value,
cvss: .vulnerabilities[0].cve.metrics.cvssMetricV31[0].cvssData.baseScore,
references: [.vulnerabilities[0].cve.references[].url]
}'
Step 1.2: Identify the affected package version range
# For npm packages, check the advisory
npm audit --json | jq '.vulnerabilities["express"] | {
name: .name,
severity: .severity,
range: .range,
fixAvailable: .fixAvailable,
via: [.via[] | if type == "object" then {title: .title, url: .url} else . end]
}'
# For Python packages
pip-audit --format=json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for vuln in data['dependencies']:
if vuln.get('vulns'):
print(json.dumps(vuln, indent=2))
"
Step 1.3: Locate the vulnerable code in the dependency source
# Find the patching commit to understand exactly what was vulnerable
# Check the CVE references for a GitHub advisory or commit link
# Example: inspect the fix commit to identify the vulnerable function
git log --oneline --all --grep="CVE-2024-29041" -- .
# Or look at the diff between vulnerable and fixed versions
npm pack [email protected] && tar -xzf express-4.18.2.tgz
npm pack [email protected] && tar -xzf express-4.19.2.tgz
diff -ru package-old/lib/ package-new/lib/
Document the finding:
cve: CVE-2024-29041
package: express
vulnerable_versions: "<4.19.2"
vulnerable_function: "res.redirect()"
vulnerable_file: "lib/response.js"
vulnerability_type: "Open Redirect"
fix_description: "Added URL validation before redirect"
Phase 2: Build the Dependency Graph
Step 2.1: Generate the full dependency tree
Node.js:
# Full dependency tree in JSON
npm ls --all --json > dependency-tree.json
# Find the specific vulnerable package in the tree
npm ls express --all
Python:
# Using pipdeptree for dependency visualization
pip install pipdeptree
pipdeptree --json > dependency-tree.json
# Find reverse dependencies (who depends on the vulnerable package)
pipdeptree --reverse --packages requests
Java (Maven):
# Full dependency tree
mvn dependency:tree -DoutputFile=dependency-tree.txt
# Find a specific dependency
mvn dependency:tree -Dincludes=com.fasterxml.jackson.core:jackson-databind
Go:
# Module dependency graph
go mod graph > dependency-graph.txt
# Why is this module in the dependency tree?
go mod why -m github.com/vulnerable/package
Step 2.2: Identify the dependency path
def trace_dependency_path(dep_tree: dict, target_package: str) -> list[list[str]]:
"""Find all paths from root to the target package in the dependency tree."""
paths = []
def dfs(node: dict, current_path: list[str]):
name = node.get("name", "root")
current_path = current_path + [name]
if name == target_package:
paths.append(current_path)
return
for dep_name, dep_info in node.get("dependencies", {}).items():
dep_info["name"] = dep_name
dfs(dep_info, current_path)
dfs(dep_tree, [])
return paths
Example output:
Dependency paths to [email protected]:
1. my-app -> [email protected] (direct)
2. my-app -> [email protected] -> [email protected] (transitive)
Phase 3: Analyze Imports and Usage
Step 3.1: Check if the vulnerable module is imported
# JavaScript/TypeScript: Find imports of the vulnerable package
grep -rn "require.*express\|from.*express" --include="*.js" --include="*.ts" src/
# Python: Find imports of the vulnerable package
grep -rn "import requests\|from requests" --include="*.py" src/
# Java: Find imports of the vulnerable class
grep -rn "import com.fasterxml.jackson" --include="*.java" src/
# Go: Find imports of the vulnerable module
grep -rn "github.com/vulnerable/package" --include="*.go" .
Step 3.2: Determine which specific functions are used
import ast
import os
def find_function_usage(codebase_path: str, module_name: str, function_name: str) -> list[dict]:
"""Find all usages of a specific function from a module in Python code."""
usages = []
for root, dirs, files in os.walk(codebase_path):
for fname in files:
if not fname.endswith(".py"):
continue
filepath = os.path.join(root, fname)
with open(filepath) as f:
try:
tree = ast.parse(f.read())
except SyntaxError:
continue
for node in ast.walk(tree):
# Check for direct function calls
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if node.func.attr == function_name:
usages.append({
"file": filepath,
"line": node.lineno,
"type": "method_call",
})
return usages
Step 3.3: Check for phantom dependencies
A phantom dependency is one that appears in the lockfile but is never actually imported:
# List all declared dependencies
jq -r '.dependencies | keys[]' package.json > declared-deps.txt
# Find which ones are actually imported
grep -roh "require(['\"][^'\"]*['\"])" --include="*.js" src/ | \
sed "s/require(['\"]//;s/['\"])//" | sort -u > imported-deps.txt
# Find phantom dependencies
comm -23 <(sort declared-deps.txt) <(sort imported-deps.txt)
Phase 4: Trace Call Paths
Step 4.1: Build the call graph from entry points to the vulnerable function
def trace_call_path(
entry_point: str,
vulnerable_function: str,
codebase_path: str,
) -> dict:
"""Trace the call path from an application entry point to a vulnerable function."""
result = {
"entry_point": entry_point,
"target": vulnerable_function,
"reachable": False,
"call_chain": [],
"evidence": [],
}
# Step 1: Start from the entry point
# Step 2: Follow function calls through the AST
# Step 3: Cross module boundaries via import resolution
# Step 4: Enter dependency code when the call crosses into node_modules/site-packages
# Step 5: Check if the vulnerable function is in the call chain
return result
Step 4.2: Use static analysis tools for automated tracing
JavaScript/TypeScript:
# Use madge for dependency graph visualization
npx madge --circular --extensions ts,js src/
# Use ts-prune to find unused exports (helps identify dead code paths)
npx ts-prune src/
Python:
# Use pyan for call graph analysis
pip install pyan3
pyan3 src/**/*.py --dot --grouped > call-graph.dot
# Use vulture to find dead code (unreachable paths)
pip install vulture
vulture src/
Java:
# Use jdeps for dependency analysis
jdeps --class-path 'lib/*' --multi-release 17 -verbose:class target/app.jar
# Check if a specific class is referenced
jdeps --class-path 'lib/*' -include 'com.vulnerable.ClassName' target/app.jar
Step 4.3: Manual tracing for complex cases
When automated tools cannot resolve the full path, trace manually:
## Manual Call Path Trace: CVE-2024-29041
### Entry Point: POST /api/auth/callback
1. `src/routes/auth.ts:45` - Route handler receives request
2. `src/routes/auth.ts:52` - Calls `authService.handleCallback(req)`
3. `src/services/auth.ts:89` - Calls `res.redirect(redirectUrl)`
4. `node_modules/express/lib/response.js:912` - Express `redirect()` method (VULNERABLE)
### Reachability: DIRECTLY REACHABLE
- The vulnerable function `res.redirect()` is called with a URL derived from query parameters
- No URL validation is applied between the entry point and the redirect call
Phase 5: Evaluate Conditions
Step 5.1: Identify conditional factors
Some vulnerabilities are reachable only under specific conditions:
conditional_factors:
configuration:
- description: "Vulnerable path only active when FEATURE_FLAG_X is enabled"
current_state: "disabled in production"
risk: "low (would become high if enabled)"
input_constraints:
- description: "Exploitation requires input > 1MB, but API has 100KB limit"
enforced_by: "nginx request_body_size"
bypassable: false
runtime_environment:
- description: "Vulnerable to SSRF only if running with network access to metadata service"
current_state: "Pod runs with restrictive NetworkPolicy"
risk: "low"
authentication:
- description: "Vulnerable endpoint requires admin role"
current_state: "Admin accounts are MFA-protected"
risk: "medium (compromised admin = exploitable)"
Step 5.2: Assess conditional reachability
def assess_conditional_reachability(conditions: list[dict]) -> dict:
"""Assess whether conditional factors make a vulnerability practically unreachable."""
blocking_conditions = []
reducing_conditions = []
for condition in conditions:
if not condition["bypassable"] and condition["current_state"] == "mitigated":
blocking_conditions.append(condition)
elif condition["risk"] in ("low", "medium"):
reducing_conditions.append(condition)
if blocking_conditions:
return {
"classification": "CONDITIONALLY_UNREACHABLE",
"blocking_factors": blocking_conditions,
"recommendation": "Monitor conditions; re-assess if configuration changes",
}
elif reducing_conditions:
return {
"classification": "CONDITIONALLY_REACHABLE",
"reducing_factors": reducing_conditions,
"recommendation": "Fix based on adjusted severity",
}
else:
return {
"classification": "REACHABLE",
"recommendation": "Fix according to severity",
}
Phase 6: Classify and Report
Step 6.1: Generate the reachability report
# CVE Reachability Analysis Report
**Project**: my-application
**Date**: 2025-01-15
**Scanner**: npm audit, Trivy
**Total CVEs Analyzed**: 23
## Summary
| Classification | Count | Percentage |
|---------------|-------|------------|
| Directly Reachable | 3 | 13% |
| Indirectly Reachable | 4 | 17% |
| Conditionally Reachable | 2 | 9% |
| Phantom Dependency | 5 | 22% |
| Unreachable | 9 | 39% |
## Directly Reachable (Immediate Fix Required)
### CVE-2024-29041: Express Open Redirect (CVSS 6.1)
- **Package**: [email protected]
- **Vulnerable Function**: `res.redirect()`
- **Call Chain**: `src/routes/auth.ts:52` -> `express/lib/response.js:912`
- **Entry Point**: `POST /api/auth/callback` (public endpoint, no authentication)
- **Recommendation**: Upgrade express to >=4.19.2
### CVE-2024-XXXXX: Prototype Pollution in lodash (CVSS 7.4)
- **Package**: [email protected]
- **Vulnerable Function**: `_.merge()`
- **Call Chain**: `src/utils/config.ts:23` -> `lodash/merge.js:45`
- **Entry Point**: `POST /api/settings` (authenticated, any user)
- **Recommendation**: Upgrade lodash to >=4.17.21
## Unreachable (No Action Required)
### CVE-2024-YYYYY: ReDoS in minimatch (CVSS 5.3)
- **Package**: [email protected] (transitive via [email protected])
- **Vulnerable Function**: `minimatch()` pattern matching
- **Evidence**: Application never calls glob or minimatch directly. Package is a build-time dependency only, not bundled into production code.
- **Classification**: PHANTOM_DEPENDENCY
- **Recommendation**: No action. Move glob to devDependencies if possible.
Step 6.2: Generate machine-readable output for CI/CD integration
{
"analysis_date": "2025-01-15T10:30:00Z",
"project": "my-application",
"findings": [
{
"cve": "CVE-2024-29041",
"package": "express",
"version": "4.18.2",
"classification": "DIRECTLY_REACHABLE",
"cvss_base": 6.1,
"call_chain": [
"src/routes/auth.ts:52",
"node_modules/express/lib/response.js:912"
],
"fix_version": "4.19.2",
"action": "UPGRADE"
},
{
"cve": "CVE-2024-YYYYY",
"package": "minimatch",
"version": "3.0.4",
"classification": "UNREACHABLE",
"cvss_base": 5.3,
"evidence": "Build-time only dependency, not in production bundle",
"action": "NONE"
}
],
"summary": {
"total": 23,
"reachable": 3,
"indirect": 4,
"conditional": 2,
"phantom": 5,
"unreachable": 9
}
}
Step 6.3: CI/CD gate configuration
# .github/workflows/cve-reachability.yml
name: CVE Reachability Check
on:
pull_request:
paths:
- "package.json"
- "package-lock.json"
- "requirements.txt"
- "go.sum"
jobs:
reachability:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run vulnerability scanner
run: npm audit --json > audit-results.json
- name: Analyze reachability
run: |
python scripts/cve-reachability.py \
--audit-results audit-results.json \
--codebase src/ \
--output reachability-report.json
- name: Gate on reachable vulnerabilities
run: |
python scripts/reachability-gate.py \
--report reachability-report.json \
--fail-on-reachable-critical \
--fail-on-reachable-high \
--allow-unreachable
Handling Special Cases
Transitive dependencies with multiple paths
When a vulnerable package is reachable through multiple dependency paths, analyze each path independently:
def analyze_all_paths(dep_tree: dict, target_package: str) -> list[dict]:
"""Analyze reachability through all dependency paths to the target."""
paths = trace_dependency_path(dep_tree, target_package)
results = []
for path in paths:
result = {
"path": " -> ".join(path),
"depth": len(path),
"reachable": False,
}
# Check if each intermediate package actually uses the next one
for i in range(len(path) - 1):
parent = path[i]
child = path[i + 1]
if not package_uses_module(parent, child):
result["blocked_at"] = f"{parent} does not import {child}"
break
else:
result["reachable"] = True
results.append(result)
return results
Runtime-only vs build-time dependencies
# Check if a dependency is in the production bundle (JavaScript)
npx webpack --stats-json
cat stats.json | jq '.modules[] | select(.name | contains("vulnerable-pkg"))'
# If the module does not appear in the bundle, it is build-time only
Best Practices
- Always identify the exact vulnerable function before analyzing reachability; "the package has a CVE" is not specific enough to determine reachability
- Use multiple analysis techniques (import analysis, call graph tracing, bundle analysis) for higher confidence
- Document the evidence for unreachable classifications so that the decision is auditable and repeatable
- Re-run reachability analysis after code changes that add new imports or dependency usages
- Distinguish between production dependencies and development/build dependencies; a CVE in a test-only dependency has different risk than one in a production dependency
- Automate reachability checks in CI/CD to catch newly reachable vulnerabilities as code evolves
- Maintain a record of analyzed CVEs and their classifications so that you do not repeat the analysis unnecessarily
- When in doubt, classify as reachable; false negatives (missing a reachable vulnerability) are more costly than false positives
- Coordinate with the security team to establish organizational thresholds for reachability-based risk acceptance
- Update the analysis when the vulnerable package publishes new information (updated advisory, proof-of-concept exploit)
Common Pitfalls
- Stopping at the import statement: A package being imported does not mean the vulnerable function is called. Trace all the way to the specific function or method.
- Ignoring dynamic dispatch: In languages with reflection, dependency injection, or dynamic imports, static analysis may miss reachable paths. Supplement with runtime tracing when possible.
- Confusing dependency declaration with usage: A package listed in
package.jsonorrequirements.txtmay never be imported. Check actual import statements, not just the manifest. - Missing transitive paths: The vulnerable function may not be called by your code directly, but by a library you use. Trace through the full dependency chain.
- Assuming build-time safety: Some build tools (Webpack, Babel plugins) execute dependency code at build time. A vulnerability in a build-time dependency could still be exploited during CI/CD.
- Overlooking dynamic loading: Plugins, middleware, and lazy-loaded modules may not appear in static import analysis. Check for
require()calls with variable arguments,importlib.import_module(), and similar dynamic loading patterns. - Not accounting for version ranges: The dependency tree may resolve to a different version than you expect. Always check the locked/resolved version, not the declared range.
- Treating all unreachable findings as permanent: Code changes can make previously unreachable vulnerabilities reachable. Reachability analysis must be continuous, not a one-time exercise.
- Relying solely on automated tools: Automated call graph tools may produce incomplete results, especially for dynamically typed languages. Combine automated analysis with manual verification for critical findings.
- Ignoring test and CI dependencies: While test dependencies do not affect production, they execute in your CI/CD environment. A compromised test dependency could inject malicious code into your build pipeline.