Map Exploit Paths with Attack Trees

Use attack trees to map exploit paths — a practical security foundations tutorial. Step-by-step guidance, hands-on examples, and troubleshooting for developers.

Focus: use attack trees to map exploit paths

Sponsored

You've locked down your app with authentication, patched dependencies, and even rolled out MFA. Yet somehow, attackers keep finding a way in — through a chain of small misconfigurations you never even considered. The gnawing feeling that you're missing exploit paths, because you can't see the full picture of your attack surface, is exactly what this lesson solves: attack trees — a structured way to map every possible path an attacker could take, so you can prioritize defenses where they matter most.

Attack trees are the X-ray for your security posture. Instead of listing random vulnerabilities, you build a hierarchical model of an attacker's goals, break them into sub-goals, and trace every conceivable route to reach those goals. By the end of this lesson, you'll be able to draw an attack tree for your own system, identify the highest-risk branches, and use that analysis to harden your defenses in a deliberate, data-driven way.

The problem this lesson solves

Traditional vulnerability scanning gives you a pile of CVEs, but it doesn't tell you which combinations of weaknesses actually lead to a compromise. Attackers think in goals — "steal the database," "take over an admin account," "deface the website." If you don't think in the same terms, you'll miss the exploit paths that chain together a low-severity misconfiguration with a medium-severity bug into a critical breach.

Without attack trees, you face three concrete problems:

  • Visibility gaps — You see individual vulnerabilities but not the stepping stones an attacker uses to reach a high-value target.
  • Prioritization paralysis — You can't decide which vulnerabilities to fix first because you don't know which ones are prerequisites for a catastrophic event.
  • Communication breakdown — Threat models live in the head of one engineer, and when they leave, the knowledge leaves with them. You have no shared visual representation to discuss risk with stakeholders, auditors, or your own team.

Attack trees solve all three by giving you a structured, reusable, and debatable model of how an attacker could achieve a specific goal.

Core concept / mental model

Think of an attack tree as a strategy map for an attacker. The root is the attacker's ultimate goal (e.g., "steal customer credit card data"). Children are the sub-goals required to achieve the parent goal (e.g., "gain access to the database," "exfiltrate the data"). Each sub-goal can be achieved through one or more attack vectors, which become further leaves in the tree.

A simple mental model: it's like a fault tree analysis (used in engineering) but from the attacker's perspective. Instead of asking "what could go wrong?" you ask "how could this fail in a harmful way?"

The two core logical operators in an attack tree are:

  • AND — All sub-goals must be achieved. (e.g., to "steal data," you must both access the data and exfiltrate it.)
  • OR — Any one sub-goal is sufficient. (e.g., to "gain access," you could phish a password, exploit a SQL injection, or use a stolen API key.)

A textual representation of a tree uses indentation to show hierarchy:

Goal: Steal customer data
  AND Access database
    OR SQL injection
    OR Phish DBA credentials
    OR Exploit exposed backup
  AND Exfiltrate data
    OR Encrypt and send via email
    OR Upload to S3 bucket
    OR Use DNS tunneling

In practice, you can also use | to denote OR and & to denote AND, but indentation is clearer for humans.

How it works step by step

Building an attack tree is a five-step process that moves from goal all the way to testable actions:

Step 1 — Define the attacker and the crown jewels

Choose a threat actor (e.g., external attacker, insider, script kiddie, APT) and a high-value asset (the database, admin panel, customer PII). The tree only makes sense when you anchor it to a specific attacker and asset.

Step 2 — Identify the attacker's primary goal

Write the goal as a single, measurable statement: "Attacker can read the customer database." Not vague like "steal data" — be precise.

Step 3 — Decompose goals into sub-goals

Ask "what must be true for the parent goal to happen?" Use AND/OR logic. Each sub-goal should be atomic enough to analyze — if it's still complex, break it down further.

Step 4 — Identify attack vectors for each leaf

For each leaf node, list concrete attack techniques, vulnerabilities, or misconfigurations that could make that sub-goal possible. Use threat intel, CVE databases, or your own architecture knowledge.

Step 5 — Annotate and prioritize

For each node, add attributes like likelihood (high/medium/low), impact (critical/high/medium), difficulty (easy/hard), detection difficulty, or cost. This lets you spot the branches that combine high impact with high likelihood — your top priorities.

Hands-on walkthrough

Let's build an attack tree for a fictional e-commerce application, shoply-dev, with a PostgreSQL database stored on AWS RDS. Your goal: map how an attacker could read all customer records.

Define and decompose

We'll represent the tree as a Python dictionary so we can programmatically analyze it:

from dataclasses import dataclass, field
from typing import Optional

@dataclass
class AttackNode:
    description: str
    operator: Optional[str] = None  # None, "AND", "OR"
    children: list = field(default_factory=list)
    likelihood: str = "medium"
    impact: str = "high"

tree = AttackNode(
    description="Attacker reads customer database",
    operator="AND",
    children=[
        AttackNode(
            description="Gain access to database",
            operator="OR",
            likelihood="medium",
            children=[
                AttackNode(description="SQL injection in product search", likelihood="low"),
                AttackNode(description="Phish DBA credentials", likelihood="medium"),
                AttackNode(description="Exploit exposed RDS snapshot", likelihood="low"),
            ],
        ),
        AttackNode(
            description="Exfiltrate data",
            operator="OR",
            likelihood="high",
            children=[
                AttackNode(description="Use database backup to S3", likelihood="medium"),
                AttackNode(description="Copy through application API", likelihood="high"),
            ],
        ),
    ],
)

Traverse to find the riskiest path

Now, a simple recursive function to find all root-to-leaf paths and score them:

def find_paths(node, path=[]):
    if not node.children:
        yield path + [node.description]
    else:
        for child in node.children:
            yield from find_paths(child, path + [node.description])

for path in find_paths(tree):
    print(" -> ".join(path))

Output:

Attacker reads customer database -> Gain access to database -> SQL injection in product search
Attacker reads customer database -> Gain access to database -> Phish DBA credentials
Attacker reads customer database -> Gain access to database -> Exploit exposed RDS snapshot
Attacker reads customer database -> Exfiltrate data -> Use database backup to S3
Attacker reads customer database -> Exfiltrate data -> Copy through application API

The tree highlights that the critical path is Phish DBA credentials + Copy through application API — both medium-to-high likelihood and high impact. That's your first priority for mitigation.

From tree to action

  • Mitigate high‑likelihood leaves — Enforce MFA for DBAs, monitor for phishing, and restrict API keys.
  • Add detection for low‑likelihood but high‑impact branches like exposed RDS snapshots.
  • Revisit the tree after every major change — a new feature could add a new branch.

Compare options / when to choose what

Attack trees are one of several threat modeling techniques. Here’s how they stack up:

Technique Strengths Weaknesses When to choose
Attack trees Visual, simple, great for prioritizing exploit paths Can become large and complex if not pruned Ideal for mapping attack paths and communicating risk to stakeholders
Threat modeling with STRIDE Systematic, covers all security categories (spoofing, tampering, repudiation, info disclosure, DoS, elevation) More abstract, not path‑centric Best for early design phase to identify categories of threats
Kill chain analysis (Lockheed Martin) Shows attacker progression from reconnaissance to actions Linear, doesn’t handle branching well Use when you want to understand attacker lifecycle and detect at each stage
DREAD / CVSS scoring Quantitative, easy to compare Subjective, doesn’t show paths Use for ranking specific vulnerabilities, not for path exploration

When to prefer attack trees:

  • You need to explore multiple alternative paths to a single goal.
  • You want to see the combinations of weaknesses (AND nodes) that lead to a breach.
  • You need a visual artifact for risk discussions.

When you need a more comprehensive view covering all threat types, combine attack trees with STRIDE. Use CVSS for individual vulnerability severity, but always feed those scores back into your attack tree for context.

Troubleshooting & edge cases

The tree becomes unmanageably large.

Beginner mistake: trying to include every possible attack technique. Solution: prune aggressively — only include realistic attack vectors for your specific environment. Use a depth limit (e.g., 5 levels) and combine similar leaves into categories like "social engineering."

Wrong parent – child relationship (AND vs OR).

Misusing the operators misrepresents the logic. Example: a data leak requires both access and exfiltration — that’s AND. If you incorrectly mark it as OR, you'll think a single step suffices and miss mitigations. Double-check each node: “If this sub‑goal alone is enough, it’s OR; if not, it’s AND.”

Missing the main goal — you build a tree around “hack the system” instead of a specific asset. You end up with vague nodes like “find a bug.” Always define a single, measurable root goal.

Ignoring the attacker’s perspective — you only think about technical exploits, forgetting that many real‑world attacks start with phishing or insider misuse. Include social engineering and insider threats as branches — they often have the highest likelihood.

Going stale — you draw the tree once, then forget it. Attack trees need to be living documents — update them when you deploy new features, change infrastructure, or learn about new CVEs that match your stack.

What you learned & what's next

You’ve learned how to use attack trees to map exploit paths — a structured approach to decompose an attacker’s goal into sub‑goals, identify AND/OR logic, and annotate nodes with likelihood and impact. You now can:

  • Explain the core idea behind attack trees and why they beat ad‑hoc vulnerability lists.
  • Build an attack tree from a high‑value asset, complete with sub‑goals and vectors.
  • Interpret the tree to prioritize the most critical paths for mitigation.
  • Apply a hands‑on Python model to visualize and analyze the paths.

You also learned that attack trees are one tool in the threat modeling toolbox — choose them when you need to map exploit paths, and combine them with STRIDE or CVSS for a fuller picture.

Next step: In the next lesson, you’ll learn how to prioritize risks from your attack tree using quantitative scoring methods like DREAD — turning your map into a ranked action plan. Keep your tree handy; you’ll feed those likelihood and impact ratings directly into your scoring matrix.

Practice recap

Grab a small service you've built (even a toy app) and define the crown-jewel asset (e.g., user database). Draw an attack tree on paper or in a Markdown file with at least 3 levels and both AND and OR nodes. Then calculate which path has the highest likelihood × impact and note a single mitigation you'd apply today. Revisit the tree after your next feature change.

Common mistakes

  • Making the tree too broad by including every possible attack vector, leading to analysis paralysis — prune to realistic branches.
  • Misusing AND/OR: treating a multi-step requirement as a single step (OR) and missing necessary mitigations.
  • Vague root goal like 'hack the system' — always anchor to a specific asset and attacker type.
  • Forgetting non-technical paths such as phishing or insider threats — these often have the highest likelihood.
  • Treating the tree as a one-time artifact and not updating it when the system changes.

Variations

  1. Use a dedicated threat modeling tool like OWASP Threat Dragon or Microsoft Threat Modeling Tool, which auto-generate trees from data-flow diagrams.
  2. Represent the tree using Graphviz DOT format instead of Python dictionaries — easier for large trees and consistent visual output.
  3. Combine attack trees with the Cyber Kill Chain to map each branch to the attacker's phase (recon → weaponize → deliver → exploit → etc.).

Real-world use cases

  • A fintech startup uses attack trees to map how an attacker could transfer money out of customer accounts — and then prioritizes MFA and anomaly detection on those critical branches.
  • A healthcare SaaS provider uses an attack tree for patient data to demonstrate compliance with HIPAA and justify security investments during an audit.
  • A DevSecOps team integrates attack tree paths into their CI/CD pipeline, failing builds that introduce a new high-likelihood exploit branch.

Key takeaways

  • Attack trees structure an attacker's goal into sub-goals with AND/OR logic, revealing all feasible exploit paths.
  • Always anchor the tree to a specific high-value asset and a threat actor to keep it useful.
  • Annotate nodes with likelihood and impact to identify the highest-risk branches for prioritization.
  • Use attack trees when you need to explore alternatives and combinations — not for ranking individual CVEs.
  • Keep the tree updated and use it as a living document to guide security decisions and risk conversations.
  • Pair attack trees with other models (STRIDE, kill chain, DREAD) for a comprehensive threat model.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.