Skip to content

Attack graph construction from network topology and vulnerability scans with MITRE ATT&CK mapping and GNN-based risk scoring

License

Notifications You must be signed in to change notification settings

cwccie/attackgraph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

attackgraph

Attack graph construction from network topology and vulnerability scan data, with MITRE ATT&CK mapping and risk scoring.

Problem

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)

Installation

pip install attackgraph

Or from source:

git clone https://github.com/cwccie/attackgraph.git
cd attackgraph
pip install -e .

Quick Start

Python API

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}")

CLI

# 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 database

Topology File Format (YAML)

topology:
  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: dmz

Vulnerability CSV Format

ip,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 overflow

Nessus CSV exports are also supported with --format nessus.

Scoring Model

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.

MITRE ATT&CK Mapping

Each attack step is automatically mapped to an ATT&CK technique using:

  1. Keyword matching on CVE descriptions (e.g., "SQL injection" → T1190, "privilege escalation" → T1068)
  2. Service-based heuristics (e.g., HTTP → T1190, SMB → T1210, VPN → T1133)
  3. Default fallback to T1210 (Exploitation of Remote Services)

Export Formats

  • JSON — full graph with metadata, suitable for further processing
  • GraphML — for visualization in Gephi, yEd, Cytoscape

Docker

docker build -t attackgraph .
docker run attackgraph --help
docker run -v $(pwd)/data:/data attackgraph build -t /data/topology.yaml -V /data/vulns.csv

Development

pip install -e .
pip install pytest pytest-cov ruff

# Run tests
pytest -v --cov=attackgraph

# Lint
ruff check src/ tests/

License

MIT License. Copyright (c) 2026 Corey Wade.

About

Attack graph construction from network topology and vulnerability scans with MITRE ATT&CK mapping and GNN-based risk scoring

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors