Claude Cursor Skill

attack-tree-construction

Build comprehensive attack trees to visualize threat paths. Use when mapping attack scenarios, identifying defense gaps, or communicating security risks to stakeholders.

LLM Mart · 0 points · 13 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download wshobson-agents-plugins_security-scanning_skills_attack-tree-construction-554237f.zip · 5 KB
Part of wshobson/agents — 170 skills

Install

skills CLI npx skills add https://github.com/wshobson/agents/tree/main/plugins/security-scanning/skills/attack-tree-construction
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wshobson-agents@llmmart
Git git clone https://github.com/wshobson/agents.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole wshobson/agents collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Attack Tree Construction

Systematic attack path visualization and analysis.

When to Use This Skill

  • Visualizing complex attack scenarios
  • Identifying defense gaps and priorities
  • Communicating risks to stakeholders
  • Planning defensive investments
  • Penetration test planning
  • Security architecture review

Core Concepts

1. Attack Tree Structure

                    [Root Goal]
                         |
            ┌────────────┴────────────┐
            │                         │
       [Sub-goal 1]              [Sub-goal 2]
       (OR node)                 (AND node)
            │                         │
      ┌─────┴─────┐             ┌─────┴─────┐
      │           │             │           │
   [Attack]   [Attack]      [Attack]   [Attack]
    (leaf)     (leaf)        (leaf)     (leaf)

2. Node Types

Type Symbol Description
OR Oval Any child achieves goal
AND Rectangle All children required
Leaf Box Atomic attack step

3. Attack Attributes

Attribute Description Values
Cost Resources needed $, $$, $$$
Time Duration to execute Hours, Days, Weeks
Skill Expertise required Low, Medium, High
Detection Likelihood of detection Low, Medium, High

Templates and detailed worked examples

Full template library lives in references/details.md. Read that file when you need concrete templates for this skill.

Best Practices

Do's

  • Start with clear goals - Define what attacker wants
  • Be exhaustive - Consider all attack vectors
  • Attribute attacks - Cost, skill, and detection
  • Update regularly - New threats emerge
  • Validate with experts - Red team review

Don'ts

  • Don't oversimplify - Real attacks are complex
  • Don't ignore dependencies - AND nodes matter
  • Don't forget insider threats - Not all attackers are external
  • Don't skip mitigations - Trees are for defense planning
  • Don't make it static - Threat landscape evolves
Files (agents)
  • references
    • details.md 19.4 KB
      # attack-tree-construction — templates and worked examples
      
      ## Templates
      
      ### Template 1: Attack Tree Data Model
      
      ```python
      from dataclasses import dataclass, field
      from enum import Enum
      from typing import List, Dict, Optional, Union
      import json
      
      class NodeType(Enum):
          OR = "or"
          AND = "and"
          LEAF = "leaf"
      
      
      class Difficulty(Enum):
          TRIVIAL = 1
          LOW = 2
          MEDIUM = 3
          HIGH = 4
          EXPERT = 5
      
      
      class Cost(Enum):
          FREE = 0
          LOW = 1
          MEDIUM = 2
          HIGH = 3
          VERY_HIGH = 4
      
      
      class DetectionRisk(Enum):
          NONE = 0
          LOW = 1
          MEDIUM = 2
          HIGH = 3
          CERTAIN = 4
      
      
      @dataclass
      class AttackAttributes:
          difficulty: Difficulty = Difficulty.MEDIUM
          cost: Cost = Cost.MEDIUM
          detection_risk: DetectionRisk = DetectionRisk.MEDIUM
          time_hours: float = 8.0
          requires_insider: bool = False
          requires_physical: bool = False
      
      
      @dataclass
      class AttackNode:
          id: str
          name: str
          description: str
          node_type: NodeType
          attributes: AttackAttributes = field(default_factory=AttackAttributes)
          children: List['AttackNode'] = field(default_factory=list)
          mitigations: List[str] = field(default_factory=list)
          cve_refs: List[str] = field(default_factory=list)
      
          def add_child(self, child: 'AttackNode') -> None:
              self.children.append(child)
      
          def calculate_path_difficulty(self) -> float:
              """Calculate aggregate difficulty for this path."""
              if self.node_type == NodeType.LEAF:
                  return self.attributes.difficulty.value
      
              if not self.children:
                  return 0
      
              child_difficulties = [c.calculate_path_difficulty() for c in self.children]
      
              if self.node_type == NodeType.OR:
                  return min(child_difficulties)
              else:  # AND
                  return max(child_difficulties)
      
          def calculate_path_cost(self) -> float:
              """Calculate aggregate cost for this path."""
              if self.node_type == NodeType.LEAF:
                  return self.attributes.cost.value
      
              if not self.children:
                  return 0
      
              child_costs = [c.calculate_path_cost() for c in self.children]
      
              if self.node_type == NodeType.OR:
                  return min(child_costs)
              else:  # AND
                  return sum(child_costs)
      
          def to_dict(self) -> Dict:
              """Convert to dictionary for serialization."""
              return {
                  "id": self.id,
                  "name": self.name,
                  "description": self.description,
                  "type": self.node_type.value,
                  "attributes": {
                      "difficulty": self.attributes.difficulty.name,
                      "cost": self.attributes.cost.name,
                      "detection_risk": self.attributes.detection_risk.name,
                      "time_hours": self.attributes.time_hours,
                  },
                  "mitigations": self.mitigations,
                  "children": [c.to_dict() for c in self.children]
              }
      
      
      @dataclass
      class AttackTree:
          name: str
          description: str
          root: AttackNode
          version: str = "1.0"
      
          def find_easiest_path(self) -> List[AttackNode]:
              """Find the path with lowest difficulty."""
              return self._find_path(self.root, minimize="difficulty")
      
          def find_cheapest_path(self) -> List[AttackNode]:
              """Find the path with lowest cost."""
              return self._find_path(self.root, minimize="cost")
      
          def find_stealthiest_path(self) -> List[AttackNode]:
              """Find the path with lowest detection risk."""
              return self._find_path(self.root, minimize="detection")
      
          def _find_path(
              self,
              node: AttackNode,
              minimize: str
          ) -> List[AttackNode]:
              """Recursive path finding."""
              if node.node_type == NodeType.LEAF:
                  return [node]
      
              if not node.children:
                  return [node]
      
              if node.node_type == NodeType.OR:
                  # Pick the best child path
                  best_path = None
                  best_score = float('inf')
      
                  for child in node.children:
                      child_path = self._find_path(child, minimize)
                      score = self._path_score(child_path, minimize)
                      if score < best_score:
                          best_score = score
                          best_path = child_path
      
                  return [node] + (best_path or [])
              else:  # AND
                  # Must traverse all children
                  path = [node]
                  for child in node.children:
                      path.extend(self._find_path(child, minimize))
                  return path
      
          def _path_score(self, path: List[AttackNode], metric: str) -> float:
              """Calculate score for a path."""
              if metric == "difficulty":
                  return sum(n.attributes.difficulty.value for n in path if n.node_type == NodeType.LEAF)
              elif metric == "cost":
                  return sum(n.attributes.cost.value for n in path if n.node_type == NodeType.LEAF)
              elif metric == "detection":
                  return sum(n.attributes.detection_risk.value for n in path if n.node_type == NodeType.LEAF)
              return 0
      
          def get_all_leaf_attacks(self) -> List[AttackNode]:
              """Get all leaf attack nodes."""
              leaves = []
              self._collect_leaves(self.root, leaves)
              return leaves
      
          def _collect_leaves(self, node: AttackNode, leaves: List[AttackNode]) -> None:
              if node.node_type == NodeType.LEAF:
                  leaves.append(node)
              for child in node.children:
                  self._collect_leaves(child, leaves)
      
          def get_unmitigated_attacks(self) -> List[AttackNode]:
              """Find attacks without mitigations."""
              return [n for n in self.get_all_leaf_attacks() if not n.mitigations]
      
          def export_json(self) -> str:
              """Export tree to JSON."""
              return json.dumps({
                  "name": self.name,
                  "description": self.description,
                  "version": self.version,
                  "root": self.root.to_dict()
              }, indent=2)
      ```
      
      ### Template 2: Attack Tree Builder
      
      ```python
      class AttackTreeBuilder:
          """Fluent builder for attack trees."""
      
          def __init__(self, name: str, description: str):
              self.name = name
              self.description = description
              self._node_stack: List[AttackNode] = []
              self._root: Optional[AttackNode] = None
      
          def goal(self, id: str, name: str, description: str = "") -> 'AttackTreeBuilder':
              """Set the root goal (OR node by default)."""
              self._root = AttackNode(
                  id=id,
                  name=name,
                  description=description,
                  node_type=NodeType.OR
              )
              self._node_stack = [self._root]
              return self
      
          def or_node(self, id: str, name: str, description: str = "") -> 'AttackTreeBuilder':
              """Add an OR sub-goal."""
              node = AttackNode(
                  id=id,
                  name=name,
                  description=description,
                  node_type=NodeType.OR
              )
              self._current().add_child(node)
              self._node_stack.append(node)
              return self
      
          def and_node(self, id: str, name: str, description: str = "") -> 'AttackTreeBuilder':
              """Add an AND sub-goal (all children required)."""
              node = AttackNode(
                  id=id,
                  name=name,
                  description=description,
                  node_type=NodeType.AND
              )
              self._current().add_child(node)
              self._node_stack.append(node)
              return self
      
          def attack(
              self,
              id: str,
              name: str,
              description: str = "",
              difficulty: Difficulty = Difficulty.MEDIUM,
              cost: Cost = Cost.MEDIUM,
              detection: DetectionRisk = DetectionRisk.MEDIUM,
              time_hours: float = 8.0,
              mitigations: List[str] = None
          ) -> 'AttackTreeBuilder':
              """Add a leaf attack node."""
              node = AttackNode(
                  id=id,
                  name=name,
                  description=description,
                  node_type=NodeType.LEAF,
                  attributes=AttackAttributes(
                      difficulty=difficulty,
                      cost=cost,
                      detection_risk=detection,
                      time_hours=time_hours
                  ),
                  mitigations=mitigations or []
              )
              self._current().add_child(node)
              return self
      
          def end(self) -> 'AttackTreeBuilder':
              """Close current node, return to parent."""
              if len(self._node_stack) > 1:
                  self._node_stack.pop()
              return self
      
          def build(self) -> AttackTree:
              """Build the attack tree."""
              if not self._root:
                  raise ValueError("No root goal defined")
              return AttackTree(
                  name=self.name,
                  description=self.description,
                  root=self._root
              )
      
          def _current(self) -> AttackNode:
              if not self._node_stack:
                  raise ValueError("No current node")
              return self._node_stack[-1]
      
      
      # Example usage
      def build_account_takeover_tree() -> AttackTree:
          """Build attack tree for account takeover scenario."""
          return (
              AttackTreeBuilder("Account Takeover", "Gain unauthorized access to user account")
              .goal("G1", "Take Over User Account")
      
              .or_node("S1", "Steal Credentials")
                  .attack(
                      "A1", "Phishing Attack",
                      difficulty=Difficulty.LOW,
                      cost=Cost.LOW,
                      detection=DetectionRisk.MEDIUM,
                      mitigations=["Security awareness training", "Email filtering"]
                  )
                  .attack(
                      "A2", "Credential Stuffing",
                      difficulty=Difficulty.TRIVIAL,
                      cost=Cost.LOW,
                      detection=DetectionRisk.HIGH,
                      mitigations=["Rate limiting", "MFA", "Password breach monitoring"]
                  )
                  .attack(
                      "A3", "Keylogger Malware",
                      difficulty=Difficulty.MEDIUM,
                      cost=Cost.MEDIUM,
                      detection=DetectionRisk.MEDIUM,
                      mitigations=["Endpoint protection", "MFA"]
                  )
              .end()
      
              .or_node("S2", "Bypass Authentication")
                  .attack(
                      "A4", "Session Hijacking",
                      difficulty=Difficulty.MEDIUM,
                      cost=Cost.LOW,
                      detection=DetectionRisk.LOW,
                      mitigations=["Secure session management", "HTTPS only"]
                  )
                  .attack(
                      "A5", "Authentication Bypass Vulnerability",
                      difficulty=Difficulty.HIGH,
                      cost=Cost.LOW,
                      detection=DetectionRisk.LOW,
                      mitigations=["Security testing", "Code review", "WAF"]
                  )
              .end()
      
              .or_node("S3", "Social Engineering")
                  .and_node("S3.1", "Account Recovery Attack")
                      .attack(
                          "A6", "Gather Personal Information",
                          difficulty=Difficulty.LOW,
                          cost=Cost.FREE,
                          detection=DetectionRisk.NONE
                      )
                      .attack(
                          "A7", "Call Support Desk",
                          difficulty=Difficulty.MEDIUM,
                          cost=Cost.FREE,
                          detection=DetectionRisk.MEDIUM,
                          mitigations=["Support verification procedures", "Security questions"]
                      )
                  .end()
              .end()
      
              .build()
          )
      ```
      
      ### Template 3: Mermaid Diagram Generator
      
      ```python
      class MermaidExporter:
          """Export attack trees to Mermaid diagram format."""
      
          def __init__(self, tree: AttackTree):
              self.tree = tree
              self._lines: List[str] = []
              self._node_count = 0
      
          def export(self) -> str:
              """Export tree to Mermaid flowchart."""
              self._lines = ["flowchart TD"]
              self._export_node(self.tree.root, None)
              return "\n".join(self._lines)
      
          def _export_node(self, node: AttackNode, parent_id: Optional[str]) -> str:
              """Recursively export nodes."""
              node_id = f"N{self._node_count}"
              self._node_count += 1
      
              # Node shape based on type
              if node.node_type == NodeType.OR:
                  shape = f"{node_id}(({node.name}))"
              elif node.node_type == NodeType.AND:
                  shape = f"{node_id}[{node.name}]"
              else:  # LEAF
                  # Color based on difficulty
                  style = self._get_leaf_style(node)
                  shape = f"{node_id}[/{node.name}/]"
                  self._lines.append(f"    style {node_id} {style}")
      
              self._lines.append(f"    {shape}")
      
              if parent_id:
                  connector = "-->" if node.node_type != NodeType.AND else "==>"
                  self._lines.append(f"    {parent_id} {connector} {node_id}")
      
              for child in node.children:
                  self._export_node(child, node_id)
      
              return node_id
      
          def _get_leaf_style(self, node: AttackNode) -> str:
              """Get style based on attack attributes."""
              colors = {
                  Difficulty.TRIVIAL: "fill:#ff6b6b",  # Red - easy attack
                  Difficulty.LOW: "fill:#ffa06b",
                  Difficulty.MEDIUM: "fill:#ffd93d",
                  Difficulty.HIGH: "fill:#6bcb77",
                  Difficulty.EXPERT: "fill:#4d96ff",  # Blue - hard attack
              }
              color = colors.get(node.attributes.difficulty, "fill:#gray")
              return color
      
      
      class PlantUMLExporter:
          """Export attack trees to PlantUML format."""
      
          def __init__(self, tree: AttackTree):
              self.tree = tree
      
          def export(self) -> str:
              """Export tree to PlantUML."""
              lines = [
                  "@startmindmap",
                  f"* {self.tree.name}",
              ]
              self._export_node(self.tree.root, lines, 1)
              lines.append("@endmindmap")
              return "\n".join(lines)
      
          def _export_node(self, node: AttackNode, lines: List[str], depth: int) -> None:
              """Recursively export nodes."""
              prefix = "*" * (depth + 1)
      
              if node.node_type == NodeType.OR:
                  marker = "[OR]"
              elif node.node_type == NodeType.AND:
                  marker = "[AND]"
              else:
                  diff = node.attributes.difficulty.name
                  marker = f"<<{diff}>>"
      
              lines.append(f"{prefix} {marker} {node.name}")
      
              for child in node.children:
                  self._export_node(child, lines, depth + 1)
      ```
      
      ### Template 4: Attack Path Analysis
      
      ```python
      from typing import Set, Tuple
      
      class AttackPathAnalyzer:
          """Analyze attack paths and coverage."""
      
          def __init__(self, tree: AttackTree):
              self.tree = tree
      
          def get_all_paths(self) -> List[List[AttackNode]]:
              """Get all possible attack paths."""
              paths = []
              self._collect_paths(self.tree.root, [], paths)
              return paths
      
          def _collect_paths(
              self,
              node: AttackNode,
              current_path: List[AttackNode],
              all_paths: List[List[AttackNode]]
          ) -> None:
              """Recursively collect all paths."""
              current_path = current_path + [node]
      
              if node.node_type == NodeType.LEAF:
                  all_paths.append(current_path)
                  return
      
              if not node.children:
                  all_paths.append(current_path)
                  return
      
              if node.node_type == NodeType.OR:
                  # Each child is a separate path
                  for child in node.children:
                      self._collect_paths(child, current_path, all_paths)
              else:  # AND
                  # Must combine all children
                  child_paths = []
                  for child in node.children:
                      child_sub_paths = []
                      self._collect_paths(child, [], child_sub_paths)
                      child_paths.append(child_sub_paths)
      
                  # Combine paths from all AND children
                  combined = self._combine_and_paths(child_paths)
                  for combo in combined:
                      all_paths.append(current_path + combo)
      
          def _combine_and_paths(
              self,
              child_paths: List[List[List[AttackNode]]]
          ) -> List[List[AttackNode]]:
              """Combine paths from AND node children."""
              if not child_paths:
                  return [[]]
      
              if len(child_paths) == 1:
                  return [path for paths in child_paths for path in paths]
      
              # Cartesian product of all child path combinations
              result = [[]]
              for paths in child_paths:
                  new_result = []
                  for existing in result:
                      for path in paths:
                          new_result.append(existing + path)
                  result = new_result
              return result
      
          def calculate_path_metrics(self, path: List[AttackNode]) -> Dict:
              """Calculate metrics for a specific path."""
              leaves = [n for n in path if n.node_type == NodeType.LEAF]
      
              total_difficulty = sum(n.attributes.difficulty.value for n in leaves)
              total_cost = sum(n.attributes.cost.value for n in leaves)
              total_time = sum(n.attributes.time_hours for n in leaves)
              max_detection = max((n.attributes.detection_risk.value for n in leaves), default=0)
      
              return {
                  "steps": len(leaves),
                  "total_difficulty": total_difficulty,
                  "avg_difficulty": total_difficulty / len(leaves) if leaves else 0,
                  "total_cost": total_cost,
                  "total_time_hours": total_time,
                  "max_detection_risk": max_detection,
                  "requires_insider": any(n.attributes.requires_insider for n in leaves),
                  "requires_physical": any(n.attributes.requires_physical for n in leaves),
              }
      
          def identify_critical_nodes(self) -> List[Tuple[AttackNode, int]]:
              """Find nodes that appear in the most paths."""
              paths = self.get_all_paths()
              node_counts: Dict[str, Tuple[AttackNode, int]] = {}
      
              for path in paths:
                  for node in path:
                      if node.id not in node_counts:
                          node_counts[node.id] = (node, 0)
                      node_counts[node.id] = (node, node_counts[node.id][1] + 1)
      
              return sorted(
                  node_counts.values(),
                  key=lambda x: x[1],
                  reverse=True
              )
      
          def coverage_analysis(self, mitigated_attacks: Set[str]) -> Dict:
              """Analyze how mitigations affect attack coverage."""
              all_paths = self.get_all_paths()
              blocked_paths = []
              open_paths = []
      
              for path in all_paths:
                  path_attacks = {n.id for n in path if n.node_type == NodeType.LEAF}
                  if path_attacks & mitigated_attacks:
                      blocked_paths.append(path)
                  else:
                      open_paths.append(path)
      
              return {
                  "total_paths": len(all_paths),
                  "blocked_paths": len(blocked_paths),
                  "open_paths": len(open_paths),
                  "coverage_percentage": len(blocked_paths) / len(all_paths) * 100 if all_paths else 0,
                  "open_path_details": [
                      {"path": [n.name for n in p], "metrics": self.calculate_path_metrics(p)}
                      for p in open_paths[:5]  # Top 5 open paths
                  ]
              }
      
          def prioritize_mitigations(self) -> List[Dict]:
              """Prioritize mitigations by impact."""
              critical_nodes = self.identify_critical_nodes()
              paths = self.get_all_paths()
              total_paths = len(paths)
      
              recommendations = []
              for node, count in critical_nodes:
                  if node.node_type == NodeType.LEAF and node.mitigations:
                      recommendations.append({
                          "attack": node.name,
                          "attack_id": node.id,
                          "paths_blocked": count,
                          "coverage_impact": count / total_paths * 100,
                          "difficulty": node.attributes.difficulty.name,
                          "mitigations": node.mitigations,
                      })
      
              return sorted(recommendations, key=lambda x: x["coverage_impact"], reverse=True)
      ```
      
  • SKILL.md 2.6 KB
    ---
    name: attack-tree-construction
    description: Build comprehensive attack trees to visualize threat paths. Use when mapping attack scenarios, identifying defense gaps, or communicating security risks to stakeholders.
    ---
    
    # Attack Tree Construction
    
    Systematic attack path visualization and analysis.
    
    ## When to Use This Skill
    
    - Visualizing complex attack scenarios
    - Identifying defense gaps and priorities
    - Communicating risks to stakeholders
    - Planning defensive investments
    - Penetration test planning
    - Security architecture review
    
    ## Core Concepts
    
    ### 1. Attack Tree Structure
    
    ```
                        [Root Goal]
                             |
                ┌────────────┴────────────┐
                │                         │
           [Sub-goal 1]              [Sub-goal 2]
           (OR node)                 (AND node)
                │                         │
          ┌─────┴─────┐             ┌─────┴─────┐
          │           │             │           │
       [Attack]   [Attack]      [Attack]   [Attack]
        (leaf)     (leaf)        (leaf)     (leaf)
    ```
    
    ### 2. Node Types
    
    | Type     | Symbol    | Description             |
    | -------- | --------- | ----------------------- |
    | **OR**   | Oval      | Any child achieves goal |
    | **AND**  | Rectangle | All children required   |
    | **Leaf** | Box       | Atomic attack step      |
    
    ### 3. Attack Attributes
    
    | Attribute     | Description             | Values             |
    | ------------- | ----------------------- | ------------------ |
    | **Cost**      | Resources needed        | $, $$, $$$         |
    | **Time**      | Duration to execute     | Hours, Days, Weeks |
    | **Skill**     | Expertise required      | Low, Medium, High  |
    | **Detection** | Likelihood of detection | Low, Medium, High  |
    
    ## Templates and detailed worked examples
    
    Full template library lives in `references/details.md`. Read that file when you need concrete templates for this skill.
    
    ## Best Practices
    
    ### Do's
    
    - **Start with clear goals** - Define what attacker wants
    - **Be exhaustive** - Consider all attack vectors
    - **Attribute attacks** - Cost, skill, and detection
    - **Update regularly** - New threats emerge
    - **Validate with experts** - Red team review
    
    ### Don'ts
    
    - **Don't oversimplify** - Real attacks are complex
    - **Don't ignore dependencies** - AND nodes matter
    - **Don't forget insider threats** - Not all attackers are external
    - **Don't skip mitigations** - Trees are for defense planning
    - **Don't make it static** - Threat landscape evolves
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related