Attack graph construction from network topology and vulnerability scan data, with MITRE ATT&CK mapping and risk scoring.
Security teams face an overwhelming volume of vulnerability scan results but lack visibility into how those vulnerabilities chain together to form actual attack paths. A single medium-severity CVE on a web server might be the first step in a multi-hop path that reaches your crown jewel database. Without attack path analysis, teams waste time on isolated findings while critical chains go unaddressed.
attackgraph solves this by:
- Building directed attack graphs from network topology + vulnerability scan data
- Computing which attack paths are actually feasible (network reachability, service matching, attack vector constraints)
- Mapping each step to MITRE ATT&CK techniques
- Scoring assets and paths by risk (CVSS, path length, asset criticality, cumulative probability)
pip install attackgraphOr from source:
git clone https://github.com/cwccie/attackgraph.git
cd attackgraph
pip install -e .from attackgraph import Asset, Vulnerability, AttackGraphBuilder
from attackgraph.scoring import RiskScorer
from attackgraph.models import AttackVector
# Define assets
web = Asset(
id="webserver",
ip="10.0.1.10",
hostname="web-01",
services=["http/80", "http/443"],
criticality=0.7,
network_zone="dmz",
)
db = Asset(
id="database",
ip="10.0.2.30",
hostname="db-01",
services=["mysql/3306"],
criticality=1.0,
network_zone="internal",
)
# Define vulnerabilities
web_vuln = Vulnerability(
cve_id="CVE-2024-1001",
cvss=9.8,
affected_service="http/80",
attack_vector=AttackVector.NETWORK,
description="Remote code execution in HTTP server",
)
db_vuln = Vulnerability(
cve_id="CVE-2024-1007",
cvss=9.1,
affected_service="mysql/3306",
attack_vector=AttackVector.NETWORK,
description="MySQL remote code execution",
)
web.vulns.append(web_vuln)
db.vulns.append(db_vuln)
# Build the attack graph
builder = AttackGraphBuilder(
topology={"webserver": ["database"]},
assets=[web, db],
)
graph = builder.build()
print(f"Nodes: {graph.node_count}, Edges: {graph.edge_count}")
# Score risks
scorer = RiskScorer(graph)
scores = scorer.score_assets()
for asset_id, score in sorted(scores.items(), key=lambda x: x[1], reverse=True):
print(f" {asset_id}: {score:.2f}")
# Find attack paths to database
paths = scorer.score_paths("database")
for p in paths:
print(f" Path: {' -> '.join(p['path'])} Score: {p['score']:.2f}")# Build an attack graph from topology and vulnerability scan
attackgraph build --topology topology.yaml --vulns scan.csv --output graph.json
# Score assets in the graph
attackgraph score graph.json
# Find attack paths to a target
attackgraph paths graph.json --target databasetopology:
firewall: [webserver]
webserver: [appserver, workstation]
appserver: [database]
assets:
firewall:
id: firewall
ip: 10.0.0.1
services: [http/443, ssh/22]
criticality: 0.9
network_zone: perimeter
webserver:
id: webserver
ip: 10.0.1.10
services: [http/80, http/443]
criticality: 0.7
network_zone: dmzip,cve_id,cvss,service,attack_vector,description
10.0.1.10,CVE-2024-1001,9.8,http/80,network,Remote code execution
10.0.2.20,CVE-2024-1004,9.0,smb/445,network,SMB buffer overflowNessus CSV exports are also supported with --format nessus.
Risk scores combine multiple factors:
- CVSS severity — weighted blend of max and average CVSS per asset
- Asset criticality — user-defined weight (0.0–1.0) reflecting business importance
- Exposure — in-degree in the attack graph (more inbound attack vectors = higher risk)
- Path probability — cumulative exploitation probability along each path
- Path length — shorter paths are more dangerous (fewer steps to compromise)
All scores are normalized to a 0.0–10.0 scale.
Each attack step is automatically mapped to an ATT&CK technique using:
- Keyword matching on CVE descriptions (e.g., "SQL injection" → T1190, "privilege escalation" → T1068)
- Service-based heuristics (e.g., HTTP → T1190, SMB → T1210, VPN → T1133)
- Default fallback to T1210 (Exploitation of Remote Services)
- JSON — full graph with metadata, suitable for further processing
- GraphML — for visualization in Gephi, yEd, Cytoscape
docker build -t attackgraph .
docker run attackgraph --help
docker run -v $(pwd)/data:/data attackgraph build -t /data/topology.yaml -V /data/vulns.csvpip install -e .
pip install pytest pytest-cov ruff
# Run tests
pytest -v --cov=attackgraph
# Lint
ruff check src/ tests/MIT License. Copyright (c) 2026 Corey Wade.