[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M70KBW9BMGH310FSBMDGSV8F":3,"skill-same:01M70KBW9BMGH310FSBMDGSV8F":62},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":33,"linkOnly":34,"markdownContent":35,"markdownBody":36,"frontMatter":37,"refName":38,"commitSha":39,"skillDirectory":40,"forksCount":41,"repositoryHtmlUrl":42,"repositoryHomepageUrl":43,"ownerHtmlUrl":44,"ownerBlogUrl":45,"ownerDescription":46,"updatedAt":47,"install":48,"resources":61},"01M70KBW9BMGH310FSBMDGSV8F","attack-tree-construction",null,"Build comprehensive attack trees to visualize threat paths. Use when mapping attack scenarios, identifying defense gaps, or communicating security risks to stakeholders.","shengdabai\u002FTony-Claude-Code-Skills","shengdabai","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F116417419?v=4","01M70F6D2WY5PQV5A92BKYJQEW","Tony Sheng","01M70F6D3GAAAYZ5H4CC1G8VXM",3,"MIT","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Fwshobson-agents\u002Fplugins\u002Fsecurity-scanning\u002Fskills\u002Fattack-tree-construction\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32],"attack tree construction","tree","trees","visualize","use","when","gaps","build","communicating","paths","defense","security","mapping","threat","2026-11-10 10:12:30",false,"---\nname: attack-tree-construction\ndescription: Build comprehensive attack trees to visualize threat paths. Use when mapping attack scenarios, identifying defense gaps, or communicating security risks to stakeholders.\n---\n\n# Attack Tree Construction\n\nSystematic attack path visualization and analysis.\n\n## When to Use This Skill\n\n- Visualizing complex attack scenarios\n- Identifying defense gaps and priorities\n- Communicating risks to stakeholders\n- Planning defensive investments\n- Penetration test planning\n- Security architecture review\n\n## Core Concepts\n\n### 1. Attack Tree Structure\n\n```\n                    [Root Goal]\n                         |\n            ┌────────────┴────────────┐\n            │                         │\n       [Sub-goal 1]              [Sub-goal 2]\n       (OR node)                 (AND node)\n            │                         │\n      ┌─────┴─────┐             ┌─────┴─────┐\n      │           │             │           │\n   [Attack]   [Attack]      [Attack]   [Attack]\n    (leaf)     (leaf)        (leaf)     (leaf)\n```\n\n### 2. Node Types\n\n| Type | Symbol | Description |\n|------|--------|-------------|\n| **OR** | Oval | Any child achieves goal |\n| **AND** | Rectangle | All children required |\n| **Leaf** | Box | Atomic attack step |\n\n### 3. Attack Attributes\n\n| Attribute | Description | Values |\n|-----------|-------------|--------|\n| **Cost** | Resources needed | $, $$, $$$ |\n| **Time** | Duration to execute | Hours, Days, Weeks |\n| **Skill** | Expertise required | Low, Medium, High |\n| **Detection** | Likelihood of detection | Low, Medium, High |\n\n## Templates\n\n### Template 1: Attack Tree Data Model\n\n```python\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nfrom typing import List, Dict, Optional, Union\nimport json\n\nclass NodeType(Enum):\n    OR = \"or\"\n    AND = \"and\"\n    LEAF = \"leaf\"\n\n\nclass Difficulty(Enum):\n    TRIVIAL = 1\n    LOW = 2\n    MEDIUM = 3\n    HIGH = 4\n    EXPERT = 5\n\n\nclass Cost(Enum):\n    FREE = 0\n    LOW = 1\n    MEDIUM = 2\n    HIGH = 3\n    VERY_HIGH = 4\n\n\nclass DetectionRisk(Enum):\n    NONE = 0\n    LOW = 1\n    MEDIUM = 2\n    HIGH = 3\n    CERTAIN = 4\n\n\n@dataclass\nclass AttackAttributes:\n    difficulty: Difficulty = Difficulty.MEDIUM\n    cost: Cost = Cost.MEDIUM\n    detection_risk: DetectionRisk = DetectionRisk.MEDIUM\n    time_hours: float = 8.0\n    requires_insider: bool = False\n    requires_physical: bool = False\n\n\n@dataclass\nclass AttackNode:\n    id: str\n    name: str\n    description: str\n    node_type: NodeType\n    attributes: AttackAttributes = field(default_factory=AttackAttributes)\n    children: List['AttackNode'] = field(default_factory=list)\n    mitigations: List[str] = field(default_factory=list)\n    cve_refs: List[str] = field(default_factory=list)\n\n    def add_child(self, child: 'AttackNode') -> None:\n        self.children.append(child)\n\n    def calculate_path_difficulty(self) -> float:\n        \"\"\"Calculate aggregate difficulty for this path.\"\"\"\n        if self.node_type == NodeType.LEAF:\n            return self.attributes.difficulty.value\n\n        if not self.children:\n            return 0\n\n        child_difficulties = [c.calculate_path_difficulty() for c in self.children]\n\n        if self.node_type == NodeType.OR:\n            return min(child_difficulties)\n        else:  # AND\n            return max(child_difficulties)\n\n    def calculate_path_cost(self) -> float:\n        \"\"\"Calculate aggregate cost for this path.\"\"\"\n        if self.node_type == NodeType.LEAF:\n            return self.attributes.cost.value\n\n        if not self.children:\n            return 0\n\n        child_costs = [c.calculate_path_cost() for c in self.children]\n\n        if self.node_type == NodeType.OR:\n            return min(child_costs)\n        else:  # AND\n            return sum(child_costs)\n\n    def to_dict(self) -> Dict:\n        \"\"\"Convert to dictionary for serialization.\"\"\"\n        return {\n            \"id\": self.id,\n            \"name\": self.name,\n            \"description\": self.description,\n            \"type\": self.node_type.value,\n            \"attributes\": {\n                \"difficulty\": self.attributes.difficulty.name,\n                \"cost\": self.attributes.cost.name,\n                \"detection_risk\": self.attributes.detection_risk.name,\n                \"time_hours\": self.attributes.time_hours,\n            },\n            \"mitigations\": self.mitigations,\n            \"children\": [c.to_dict() for c in self.children]\n        }\n\n\n@dataclass\nclass AttackTree:\n    name: str\n    description: str\n    root: AttackNode\n    version: str = \"1.0\"\n\n    def find_easiest_path(self) -> List[AttackNode]:\n        \"\"\"Find the path with lowest difficulty.\"\"\"\n        return self._find_path(self.root, minimize=\"difficulty\")\n\n    def find_cheapest_path(self) -> List[AttackNode]:\n        \"\"\"Find the path with lowest cost.\"\"\"\n        return self._find_path(self.root, minimize=\"cost\")\n\n    def find_stealthiest_path(self) -> List[AttackNode]:\n        \"\"\"Find the path with lowest detection risk.\"\"\"\n        return self._find_path(self.root, minimize=\"detection\")\n\n    def _find_path(\n        self,\n        node: AttackNode,\n        minimize: str\n    ) -> List[AttackNode]:\n        \"\"\"Recursive path finding.\"\"\"\n        if node.node_type == NodeType.LEAF:\n            return [node]\n\n        if not node.children:\n            return [node]\n\n        if node.node_type == NodeType.OR:\n            # Pick the best child path\n            best_path = None\n            best_score = float('inf')\n\n            for child in node.children:\n                child_path = self._find_path(child, minimize)\n                score = self._path_score(child_path, minimize)\n                if score \u003C best_score:\n                    best_score = score\n                    best_path = child_path\n\n            return [node] + (best_path or [])\n        else:  # AND\n            # Must traverse all children\n            path = [node]\n            for child in node.children:\n                path.extend(self._find_path(child, minimize))\n            return path\n\n    def _path_score(self, path: List[AttackNode], metric: str) -> float:\n        \"\"\"Calculate score for a path.\"\"\"\n        if metric == \"difficulty\":\n            return sum(n.attributes.difficulty.value for n in path if n.node_type == NodeType.LEAF)\n        elif metric == \"cost\":\n            return sum(n.attributes.cost.value for n in path if n.node_type == NodeType.LEAF)\n        elif metric == \"detection\":\n            return sum(n.attributes.detection_risk.value for n in path if n.node_type == NodeType.LEAF)\n        return 0\n\n    def get_all_leaf_attacks(self) -> List[AttackNode]:\n        \"\"\"Get all leaf attack nodes.\"\"\"\n        leaves = []\n        self._collect_leaves(self.root, leaves)\n        return leaves\n\n    def _collect_leaves(self, node: AttackNode, leaves: List[AttackNode]) -> None:\n        if node.node_type == NodeType.LEAF:\n            leaves.append(node)\n        for child in node.children:\n            self._collect_leaves(child, leaves)\n\n    def get_unmitigated_attacks(self) -> List[AttackNode]:\n        \"\"\"Find attacks without mitigations.\"\"\"\n        return [n for n in self.get_all_leaf_attacks() if not n.mitigations]\n\n    def export_json(self) -> str:\n        \"\"\"Export tree to JSON.\"\"\"\n        return json.dumps({\n            \"name\": self.name,\n            \"description\": self.description,\n            \"version\": self.version,\n            \"root\": self.root.to_dict()\n        }, indent=2)\n```\n\n### Template 2: Attack Tree Builder\n\n```python\nclass AttackTreeBuilder:\n    \"\"\"Fluent builder for attack trees.\"\"\"\n\n    def __init__(self, name: str, description: str):\n        self.name = name\n        self.description = description\n        self._node_stack: List[AttackNode] = []\n        self._root: Optional[AttackNode] = None\n\n    def goal(self, id: str, name: str, description: str = \"\") -> 'AttackTreeBuilder':\n        \"\"\"Set the root goal (OR node by default).\"\"\"\n        self._root = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.OR\n        )\n        self._node_stack = [self._root]\n        return self\n\n    def or_node(self, id: str, name: str, description: str = \"\") -> 'AttackTreeBuilder':\n        \"\"\"Add an OR sub-goal.\"\"\"\n        node = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.OR\n        )\n        self._current().add_child(node)\n        self._node_stack.append(node)\n        return self\n\n    def and_node(self, id: str, name: str, description: str = \"\") -> 'AttackTreeBuilder':\n        \"\"\"Add an AND sub-goal (all children required).\"\"\"\n        node = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.AND\n        )\n        self._current().add_child(node)\n        self._node_stack.append(node)\n        return self\n\n    def attack(\n        self,\n        id: str,\n        name: str,\n        description: str = \"\",\n        difficulty: Difficulty = Difficulty.MEDIUM,\n        cost: Cost = Cost.MEDIUM,\n        detection: DetectionRisk = DetectionRisk.MEDIUM,\n        time_hours: float = 8.0,\n        mitigations: List[str] = None\n    ) -> 'AttackTreeBuilder':\n        \"\"\"Add a leaf attack node.\"\"\"\n        node = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.LEAF,\n            attributes=AttackAttributes(\n                difficulty=difficulty,\n                cost=cost,\n                detection_risk=detection,\n                time_hours=time_hours\n            ),\n            mitigations=mitigations or []\n        )\n        self._current().add_child(node)\n        return self\n\n    def end(self) -> 'AttackTreeBuilder':\n        \"\"\"Close current node, return to parent.\"\"\"\n        if len(self._node_stack) > 1:\n            self._node_stack.pop()\n        return self\n\n    def build(self) -> AttackTree:\n        \"\"\"Build the attack tree.\"\"\"\n        if not self._root:\n            raise ValueError(\"No root goal defined\")\n        return AttackTree(\n            name=self.name,\n            description=self.description,\n            root=self._root\n        )\n\n    def _current(self) -> AttackNode:\n        if not self._node_stack:\n            raise ValueError(\"No current node\")\n        return self._node_stack[-1]\n\n\n# Example usage\ndef build_account_takeover_tree() -> AttackTree:\n    \"\"\"Build attack tree for account takeover scenario.\"\"\"\n    return (\n        AttackTreeBuilder(\"Account Takeover\", \"Gain unauthorized access to user account\")\n        .goal(\"G1\", \"Take Over User Account\")\n\n        .or_node(\"S1\", \"Steal Credentials\")\n            .attack(\n                \"A1\", \"Phishing Attack\",\n                difficulty=Difficulty.LOW,\n                cost=Cost.LOW,\n                detection=DetectionRisk.MEDIUM,\n                mitigations=[\"Security awareness training\", \"Email filtering\"]\n            )\n            .attack(\n                \"A2\", \"Credential Stuffing\",\n                difficulty=Difficulty.TRIVIAL,\n                cost=Cost.LOW,\n                detection=DetectionRisk.HIGH,\n                mitigations=[\"Rate limiting\", \"MFA\", \"Password breach monitoring\"]\n            )\n            .attack(\n                \"A3\", \"Keylogger Malware\",\n                difficulty=Difficulty.MEDIUM,\n                cost=Cost.MEDIUM,\n                detection=DetectionRisk.MEDIUM,\n                mitigations=[\"Endpoint protection\", \"MFA\"]\n            )\n        .end()\n\n        .or_node(\"S2\", \"Bypass Authentication\")\n            .attack(\n                \"A4\", \"Session Hijacking\",\n                difficulty=Difficulty.MEDIUM,\n                cost=Cost.LOW,\n                detection=DetectionRisk.LOW,\n                mitigations=[\"Secure session management\", \"HTTPS only\"]\n            )\n            .attack(\n                \"A5\", \"Authentication Bypass Vulnerability\",\n                difficulty=Difficulty.HIGH,\n                cost=Cost.LOW,\n                detection=DetectionRisk.LOW,\n                mitigations=[\"Security testing\", \"Code review\", \"WAF\"]\n            )\n        .end()\n\n        .or_node(\"S3\", \"Social Engineering\")\n            .and_node(\"S3.1\", \"Account Recovery Attack\")\n                .attack(\n                    \"A6\", \"Gather Personal Information\",\n                    difficulty=Difficulty.LOW,\n                    cost=Cost.FREE,\n                    detection=DetectionRisk.NONE\n                )\n                .attack(\n                    \"A7\", \"Call Support Desk\",\n                    difficulty=Difficulty.MEDIUM,\n                    cost=Cost.FREE,\n                    detection=DetectionRisk.MEDIUM,\n                    mitigations=[\"Support verification procedures\", \"Security questions\"]\n                )\n            .end()\n        .end()\n\n        .build()\n    )\n```\n\n### Template 3: Mermaid Diagram Generator\n\n```python\nclass MermaidExporter:\n    \"\"\"Export attack trees to Mermaid diagram format.\"\"\"\n\n    def __init__(self, tree: AttackTree):\n        self.tree = tree\n        self._lines: List[str] = []\n        self._node_count = 0\n\n    def export(self) -> str:\n        \"\"\"Export tree to Mermaid flowchart.\"\"\"\n        self._lines = [\"flowchart TD\"]\n        self._export_node(self.tree.root, None)\n        return \"\\n\".join(self._lines)\n\n    def _export_node(self, node: AttackNode, parent_id: Optional[str]) -> str:\n        \"\"\"Recursively export nodes.\"\"\"\n        node_id = f\"N{self._node_count}\"\n        self._node_count += 1\n\n        # Node shape based on type\n        if node.node_type == NodeType.OR:\n            shape = f\"{node_id}(({node.name}))\"\n        elif node.node_type == NodeType.AND:\n            shape = f\"{node_id}[{node.name}]\"\n        else:  # LEAF\n            # Color based on difficulty\n            style = self._get_leaf_style(node)\n            shape = f\"{node_id}[\u002F{node.name}\u002F]\"\n            self._lines.append(f\"    style {node_id} {style}\")\n\n        self._lines.append(f\"    {shape}\")\n\n        if parent_id:\n            connector = \"-->\" if node.node_type != NodeType.AND else \"==>\"\n            self._lines.append(f\"    {parent_id} {connector} {node_id}\")\n\n        for child in node.children:\n            self._export_node(child, node_id)\n\n        return node_id\n\n    def _get_leaf_style(self, node: AttackNode) -> str:\n        \"\"\"Get style based on attack attributes.\"\"\"\n        colors = {\n            Difficulty.TRIVIAL: \"fill:#ff6b6b\",  # Red - easy attack\n            Difficulty.LOW: \"fill:#ffa06b\",\n            Difficulty.MEDIUM: \"fill:#ffd93d\",\n            Difficulty.HIGH: \"fill:#6bcb77\",\n            Difficulty.EXPERT: \"fill:#4d96ff\",  # Blue - hard attack\n        }\n        color = colors.get(node.attributes.difficulty, \"fill:#gray\")\n        return color\n\n\nclass PlantUMLExporter:\n    \"\"\"Export attack trees to PlantUML format.\"\"\"\n\n    def __init__(self, tree: AttackTree):\n        self.tree = tree\n\n    def export(self) -> str:\n        \"\"\"Export tree to PlantUML.\"\"\"\n        lines = [\n            \"@startmindmap\",\n            f\"* {self.tree.name}\",\n        ]\n        self._export_node(self.tree.root, lines, 1)\n        lines.append(\"@endmindmap\")\n        return \"\\n\".join(lines)\n\n    def _export_node(self, node: AttackNode, lines: List[str], depth: int) -> None:\n        \"\"\"Recursively export nodes.\"\"\"\n        prefix = \"*\" * (depth + 1)\n\n        if node.node_type == NodeType.OR:\n            marker = \"[OR]\"\n        elif node.node_type == NodeType.AND:\n            marker = \"[AND]\"\n        else:\n            diff = node.attributes.difficulty.name\n            marker = f\"\u003C\u003C{diff}>>\"\n\n        lines.append(f\"{prefix} {marker} {node.name}\")\n\n        for child in node.children:\n            self._export_node(child, lines, depth + 1)\n```\n\n### Template 4: Attack Path Analysis\n\n```python\nfrom typing import Set, Tuple\n\nclass AttackPathAnalyzer:\n    \"\"\"Analyze attack paths and coverage.\"\"\"\n\n    def __init__(self, tree: AttackTree):\n        self.tree = tree\n\n    def get_all_paths(self) -> List[List[AttackNode]]:\n        \"\"\"Get all possible attack paths.\"\"\"\n        paths = []\n        self._collect_paths(self.tree.root, [], paths)\n        return paths\n\n    def _collect_paths(\n        self,\n        node: AttackNode,\n        current_path: List[AttackNode],\n        all_paths: List[List[AttackNode]]\n    ) -> None:\n        \"\"\"Recursively collect all paths.\"\"\"\n        current_path = current_path + [node]\n\n        if node.node_type == NodeType.LEAF:\n            all_paths.append(current_path)\n            return\n\n        if not node.children:\n            all_paths.append(current_path)\n            return\n\n        if node.node_type == NodeType.OR:\n            # Each child is a separate path\n            for child in node.children:\n                self._collect_paths(child, current_path, all_paths)\n        else:  # AND\n            # Must combine all children\n            child_paths = []\n            for child in node.children:\n                child_sub_paths = []\n                self._collect_paths(child, [], child_sub_paths)\n                child_paths.append(child_sub_paths)\n\n            # Combine paths from all AND children\n            combined = self._combine_and_paths(child_paths)\n            for combo in combined:\n                all_paths.append(current_path + combo)\n\n    def _combine_and_paths(\n        self,\n        child_paths: List[List[List[AttackNode]]]\n    ) -> List[List[AttackNode]]:\n        \"\"\"Combine paths from AND node children.\"\"\"\n        if not child_paths:\n            return [[]]\n\n        if len(child_paths) == 1:\n            return [path for paths in child_paths for path in paths]\n\n        # Cartesian product of all child path combinations\n        result = [[]]\n        for paths in child_paths:\n            new_result = []\n            for existing in result:\n                for path in paths:\n                    new_result.append(existing + path)\n            result = new_result\n        return result\n\n    def calculate_path_metrics(self, path: List[AttackNode]) -> Dict:\n        \"\"\"Calculate metrics for a specific path.\"\"\"\n        leaves = [n for n in path if n.node_type == NodeType.LEAF]\n\n        total_difficulty = sum(n.attributes.difficulty.value for n in leaves)\n        total_cost = sum(n.attributes.cost.value for n in leaves)\n        total_time = sum(n.attributes.time_hours for n in leaves)\n        max_detection = max((n.attributes.detection_risk.value for n in leaves), default=0)\n\n        return {\n            \"steps\": len(leaves),\n            \"total_difficulty\": total_difficulty,\n            \"avg_difficulty\": total_difficulty \u002F len(leaves) if leaves else 0,\n            \"total_cost\": total_cost,\n            \"total_time_hours\": total_time,\n            \"max_detection_risk\": max_detection,\n            \"requires_insider\": any(n.attributes.requires_insider for n in leaves),\n            \"requires_physical\": any(n.attributes.requires_physical for n in leaves),\n        }\n\n    def identify_critical_nodes(self) -> List[Tuple[AttackNode, int]]:\n        \"\"\"Find nodes that appear in the most paths.\"\"\"\n        paths = self.get_all_paths()\n        node_counts: Dict[str, Tuple[AttackNode, int]] = {}\n\n        for path in paths:\n            for node in path:\n                if node.id not in node_counts:\n                    node_counts[node.id] = (node, 0)\n                node_counts[node.id] = (node, node_counts[node.id][1] + 1)\n\n        return sorted(\n            node_counts.values(),\n            key=lambda x: x[1],\n            reverse=True\n        )\n\n    def coverage_analysis(self, mitigated_attacks: Set[str]) -> Dict:\n        \"\"\"Analyze how mitigations affect attack coverage.\"\"\"\n        all_paths = self.get_all_paths()\n        blocked_paths = []\n        open_paths = []\n\n        for path in all_paths:\n            path_attacks = {n.id for n in path if n.node_type == NodeType.LEAF}\n            if path_attacks & mitigated_attacks:\n                blocked_paths.append(path)\n            else:\n                open_paths.append(path)\n\n        return {\n            \"total_paths\": len(all_paths),\n            \"blocked_paths\": len(blocked_paths),\n            \"open_paths\": len(open_paths),\n            \"coverage_percentage\": len(blocked_paths) \u002F len(all_paths) * 100 if all_paths else 0,\n            \"open_path_details\": [\n                {\"path\": [n.name for n in p], \"metrics\": self.calculate_path_metrics(p)}\n                for p in open_paths[:5]  # Top 5 open paths\n            ]\n        }\n\n    def prioritize_mitigations(self) -> List[Dict]:\n        \"\"\"Prioritize mitigations by impact.\"\"\"\n        critical_nodes = self.identify_critical_nodes()\n        paths = self.get_all_paths()\n        total_paths = len(paths)\n\n        recommendations = []\n        for node, count in critical_nodes:\n            if node.node_type == NodeType.LEAF and node.mitigations:\n                recommendations.append({\n                    \"attack\": node.name,\n                    \"attack_id\": node.id,\n                    \"paths_blocked\": count,\n                    \"coverage_impact\": count \u002F total_paths * 100,\n                    \"difficulty\": node.attributes.difficulty.name,\n                    \"mitigations\": node.mitigations,\n                })\n\n        return sorted(recommendations, key=lambda x: x[\"coverage_impact\"], reverse=True)\n```\n\n## Best Practices\n\n### Do's\n- **Start with clear goals** - Define what attacker wants\n- **Be exhaustive** - Consider all attack vectors\n- **Attribute attacks** - Cost, skill, and detection\n- **Update regularly** - New threats emerge\n- **Validate with experts** - Red team review\n\n### Don'ts\n- **Don't oversimplify** - Real attacks are complex\n- **Don't ignore dependencies** - AND nodes matter\n- **Don't forget insider threats** - Not all attackers are external\n- **Don't skip mitigations** - Trees are for defense planning\n- **Don't make it static** - Threat landscape evolves\n\n## Resources\n\n- [Attack Trees by Bruce Schneier](https:\u002F\u002Fwww.schneier.com\u002Facademic\u002Farchives\u002F1999\u002F12\u002Fattack_trees.html)\n- [MITRE ATT&CK Framework](https:\u002F\u002Fattack.mitre.org\u002F)\n- [OWASP Attack Surface Analysis](https:\u002F\u002Fowasp.org\u002Fwww-community\u002Fcontrols\u002FAttack_Surface_Analysis_Cheat_Sheet)\n","# Attack Tree Construction\n\nSystematic attack path visualization and analysis.\n\n## When to Use This Skill\n\n- Visualizing complex attack scenarios\n- Identifying defense gaps and priorities\n- Communicating risks to stakeholders\n- Planning defensive investments\n- Penetration test planning\n- Security architecture review\n\n## Core Concepts\n\n### 1. Attack Tree Structure\n\n```\n                    [Root Goal]\n                         |\n            ┌────────────┴────────────┐\n            │                         │\n       [Sub-goal 1]              [Sub-goal 2]\n       (OR node)                 (AND node)\n            │                         │\n      ┌─────┴─────┐             ┌─────┴─────┐\n      │           │             │           │\n   [Attack]   [Attack]      [Attack]   [Attack]\n    (leaf)     (leaf)        (leaf)     (leaf)\n```\n\n### 2. Node Types\n\n| Type | Symbol | Description |\n|------|--------|-------------|\n| **OR** | Oval | Any child achieves goal |\n| **AND** | Rectangle | All children required |\n| **Leaf** | Box | Atomic attack step |\n\n### 3. Attack Attributes\n\n| Attribute | Description | Values |\n|-----------|-------------|--------|\n| **Cost** | Resources needed | $, $$, $$$ |\n| **Time** | Duration to execute | Hours, Days, Weeks |\n| **Skill** | Expertise required | Low, Medium, High |\n| **Detection** | Likelihood of detection | Low, Medium, High |\n\n## Templates\n\n### Template 1: Attack Tree Data Model\n\n```python\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nfrom typing import List, Dict, Optional, Union\nimport json\n\nclass NodeType(Enum):\n    OR = \"or\"\n    AND = \"and\"\n    LEAF = \"leaf\"\n\n\nclass Difficulty(Enum):\n    TRIVIAL = 1\n    LOW = 2\n    MEDIUM = 3\n    HIGH = 4\n    EXPERT = 5\n\n\nclass Cost(Enum):\n    FREE = 0\n    LOW = 1\n    MEDIUM = 2\n    HIGH = 3\n    VERY_HIGH = 4\n\n\nclass DetectionRisk(Enum):\n    NONE = 0\n    LOW = 1\n    MEDIUM = 2\n    HIGH = 3\n    CERTAIN = 4\n\n\n@dataclass\nclass AttackAttributes:\n    difficulty: Difficulty = Difficulty.MEDIUM\n    cost: Cost = Cost.MEDIUM\n    detection_risk: DetectionRisk = DetectionRisk.MEDIUM\n    time_hours: float = 8.0\n    requires_insider: bool = False\n    requires_physical: bool = False\n\n\n@dataclass\nclass AttackNode:\n    id: str\n    name: str\n    description: str\n    node_type: NodeType\n    attributes: AttackAttributes = field(default_factory=AttackAttributes)\n    children: List['AttackNode'] = field(default_factory=list)\n    mitigations: List[str] = field(default_factory=list)\n    cve_refs: List[str] = field(default_factory=list)\n\n    def add_child(self, child: 'AttackNode') -> None:\n        self.children.append(child)\n\n    def calculate_path_difficulty(self) -> float:\n        \"\"\"Calculate aggregate difficulty for this path.\"\"\"\n        if self.node_type == NodeType.LEAF:\n            return self.attributes.difficulty.value\n\n        if not self.children:\n            return 0\n\n        child_difficulties = [c.calculate_path_difficulty() for c in self.children]\n\n        if self.node_type == NodeType.OR:\n            return min(child_difficulties)\n        else:  # AND\n            return max(child_difficulties)\n\n    def calculate_path_cost(self) -> float:\n        \"\"\"Calculate aggregate cost for this path.\"\"\"\n        if self.node_type == NodeType.LEAF:\n            return self.attributes.cost.value\n\n        if not self.children:\n            return 0\n\n        child_costs = [c.calculate_path_cost() for c in self.children]\n\n        if self.node_type == NodeType.OR:\n            return min(child_costs)\n        else:  # AND\n            return sum(child_costs)\n\n    def to_dict(self) -> Dict:\n        \"\"\"Convert to dictionary for serialization.\"\"\"\n        return {\n            \"id\": self.id,\n            \"name\": self.name,\n            \"description\": self.description,\n            \"type\": self.node_type.value,\n            \"attributes\": {\n                \"difficulty\": self.attributes.difficulty.name,\n                \"cost\": self.attributes.cost.name,\n                \"detection_risk\": self.attributes.detection_risk.name,\n                \"time_hours\": self.attributes.time_hours,\n            },\n            \"mitigations\": self.mitigations,\n            \"children\": [c.to_dict() for c in self.children]\n        }\n\n\n@dataclass\nclass AttackTree:\n    name: str\n    description: str\n    root: AttackNode\n    version: str = \"1.0\"\n\n    def find_easiest_path(self) -> List[AttackNode]:\n        \"\"\"Find the path with lowest difficulty.\"\"\"\n        return self._find_path(self.root, minimize=\"difficulty\")\n\n    def find_cheapest_path(self) -> List[AttackNode]:\n        \"\"\"Find the path with lowest cost.\"\"\"\n        return self._find_path(self.root, minimize=\"cost\")\n\n    def find_stealthiest_path(self) -> List[AttackNode]:\n        \"\"\"Find the path with lowest detection risk.\"\"\"\n        return self._find_path(self.root, minimize=\"detection\")\n\n    def _find_path(\n        self,\n        node: AttackNode,\n        minimize: str\n    ) -> List[AttackNode]:\n        \"\"\"Recursive path finding.\"\"\"\n        if node.node_type == NodeType.LEAF:\n            return [node]\n\n        if not node.children:\n            return [node]\n\n        if node.node_type == NodeType.OR:\n            # Pick the best child path\n            best_path = None\n            best_score = float('inf')\n\n            for child in node.children:\n                child_path = self._find_path(child, minimize)\n                score = self._path_score(child_path, minimize)\n                if score \u003C best_score:\n                    best_score = score\n                    best_path = child_path\n\n            return [node] + (best_path or [])\n        else:  # AND\n            # Must traverse all children\n            path = [node]\n            for child in node.children:\n                path.extend(self._find_path(child, minimize))\n            return path\n\n    def _path_score(self, path: List[AttackNode], metric: str) -> float:\n        \"\"\"Calculate score for a path.\"\"\"\n        if metric == \"difficulty\":\n            return sum(n.attributes.difficulty.value for n in path if n.node_type == NodeType.LEAF)\n        elif metric == \"cost\":\n            return sum(n.attributes.cost.value for n in path if n.node_type == NodeType.LEAF)\n        elif metric == \"detection\":\n            return sum(n.attributes.detection_risk.value for n in path if n.node_type == NodeType.LEAF)\n        return 0\n\n    def get_all_leaf_attacks(self) -> List[AttackNode]:\n        \"\"\"Get all leaf attack nodes.\"\"\"\n        leaves = []\n        self._collect_leaves(self.root, leaves)\n        return leaves\n\n    def _collect_leaves(self, node: AttackNode, leaves: List[AttackNode]) -> None:\n        if node.node_type == NodeType.LEAF:\n            leaves.append(node)\n        for child in node.children:\n            self._collect_leaves(child, leaves)\n\n    def get_unmitigated_attacks(self) -> List[AttackNode]:\n        \"\"\"Find attacks without mitigations.\"\"\"\n        return [n for n in self.get_all_leaf_attacks() if not n.mitigations]\n\n    def export_json(self) -> str:\n        \"\"\"Export tree to JSON.\"\"\"\n        return json.dumps({\n            \"name\": self.name,\n            \"description\": self.description,\n            \"version\": self.version,\n            \"root\": self.root.to_dict()\n        }, indent=2)\n```\n\n### Template 2: Attack Tree Builder\n\n```python\nclass AttackTreeBuilder:\n    \"\"\"Fluent builder for attack trees.\"\"\"\n\n    def __init__(self, name: str, description: str):\n        self.name = name\n        self.description = description\n        self._node_stack: List[AttackNode] = []\n        self._root: Optional[AttackNode] = None\n\n    def goal(self, id: str, name: str, description: str = \"\") -> 'AttackTreeBuilder':\n        \"\"\"Set the root goal (OR node by default).\"\"\"\n        self._root = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.OR\n        )\n        self._node_stack = [self._root]\n        return self\n\n    def or_node(self, id: str, name: str, description: str = \"\") -> 'AttackTreeBuilder':\n        \"\"\"Add an OR sub-goal.\"\"\"\n        node = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.OR\n        )\n        self._current().add_child(node)\n        self._node_stack.append(node)\n        return self\n\n    def and_node(self, id: str, name: str, description: str = \"\") -> 'AttackTreeBuilder':\n        \"\"\"Add an AND sub-goal (all children required).\"\"\"\n        node = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.AND\n        )\n        self._current().add_child(node)\n        self._node_stack.append(node)\n        return self\n\n    def attack(\n        self,\n        id: str,\n        name: str,\n        description: str = \"\",\n        difficulty: Difficulty = Difficulty.MEDIUM,\n        cost: Cost = Cost.MEDIUM,\n        detection: DetectionRisk = DetectionRisk.MEDIUM,\n        time_hours: float = 8.0,\n        mitigations: List[str] = None\n    ) -> 'AttackTreeBuilder':\n        \"\"\"Add a leaf attack node.\"\"\"\n        node = AttackNode(\n            id=id,\n            name=name,\n            description=description,\n            node_type=NodeType.LEAF,\n            attributes=AttackAttributes(\n                difficulty=difficulty,\n                cost=cost,\n                detection_risk=detection,\n                time_hours=time_hours\n            ),\n            mitigations=mitigations or []\n        )\n        self._current().add_child(node)\n        return self\n\n    def end(self) -> 'AttackTreeBuilder':\n        \"\"\"Close current node, return to parent.\"\"\"\n        if len(self._node_stack) > 1:\n            self._node_stack.pop()\n        return self\n\n    def build(self) -> AttackTree:\n        \"\"\"Build the attack tree.\"\"\"\n        if not self._root:\n            raise ValueError(\"No root goal defined\")\n        return AttackTree(\n            name=self.name,\n            description=self.description,\n            root=self._root\n        )\n\n    def _current(self) -> AttackNode:\n        if not self._node_stack:\n            raise ValueError(\"No current node\")\n        return self._node_stack[-1]\n\n\n# Example usage\ndef build_account_takeover_tree() -> AttackTree:\n    \"\"\"Build attack tree for account takeover scenario.\"\"\"\n    return (\n        AttackTreeBuilder(\"Account Takeover\", \"Gain unauthorized access to user account\")\n        .goal(\"G1\", \"Take Over User Account\")\n\n        .or_node(\"S1\", \"Steal Credentials\")\n            .attack(\n                \"A1\", \"Phishing Attack\",\n                difficulty=Difficulty.LOW,\n                cost=Cost.LOW,\n                detection=DetectionRisk.MEDIUM,\n                mitigations=[\"Security awareness training\", \"Email filtering\"]\n            )\n            .attack(\n                \"A2\", \"Credential Stuffing\",\n                difficulty=Difficulty.TRIVIAL,\n                cost=Cost.LOW,\n                detection=DetectionRisk.HIGH,\n                mitigations=[\"Rate limiting\", \"MFA\", \"Password breach monitoring\"]\n            )\n            .attack(\n                \"A3\", \"Keylogger Malware\",\n                difficulty=Difficulty.MEDIUM,\n                cost=Cost.MEDIUM,\n                detection=DetectionRisk.MEDIUM,\n                mitigations=[\"Endpoint protection\", \"MFA\"]\n            )\n        .end()\n\n        .or_node(\"S2\", \"Bypass Authentication\")\n            .attack(\n                \"A4\", \"Session Hijacking\",\n                difficulty=Difficulty.MEDIUM,\n                cost=Cost.LOW,\n                detection=DetectionRisk.LOW,\n                mitigations=[\"Secure session management\", \"HTTPS only\"]\n            )\n            .attack(\n                \"A5\", \"Authentication Bypass Vulnerability\",\n                difficulty=Difficulty.HIGH,\n                cost=Cost.LOW,\n                detection=DetectionRisk.LOW,\n                mitigations=[\"Security testing\", \"Code review\", \"WAF\"]\n            )\n        .end()\n\n        .or_node(\"S3\", \"Social Engineering\")\n            .and_node(\"S3.1\", \"Account Recovery Attack\")\n                .attack(\n                    \"A6\", \"Gather Personal Information\",\n                    difficulty=Difficulty.LOW,\n                    cost=Cost.FREE,\n                    detection=DetectionRisk.NONE\n                )\n                .attack(\n                    \"A7\", \"Call Support Desk\",\n                    difficulty=Difficulty.MEDIUM,\n                    cost=Cost.FREE,\n                    detection=DetectionRisk.MEDIUM,\n                    mitigations=[\"Support verification procedures\", \"Security questions\"]\n                )\n            .end()\n        .end()\n\n        .build()\n    )\n```\n\n### Template 3: Mermaid Diagram Generator\n\n```python\nclass MermaidExporter:\n    \"\"\"Export attack trees to Mermaid diagram format.\"\"\"\n\n    def __init__(self, tree: AttackTree):\n        self.tree = tree\n        self._lines: List[str] = []\n        self._node_count = 0\n\n    def export(self) -> str:\n        \"\"\"Export tree to Mermaid flowchart.\"\"\"\n        self._lines = [\"flowchart TD\"]\n        self._export_node(self.tree.root, None)\n        return \"\\n\".join(self._lines)\n\n    def _export_node(self, node: AttackNode, parent_id: Optional[str]) -> str:\n        \"\"\"Recursively export nodes.\"\"\"\n        node_id = f\"N{self._node_count}\"\n        self._node_count += 1\n\n        # Node shape based on type\n        if node.node_type == NodeType.OR:\n            shape = f\"{node_id}(({node.name}))\"\n        elif node.node_type == NodeType.AND:\n            shape = f\"{node_id}[{node.name}]\"\n        else:  # LEAF\n            # Color based on difficulty\n            style = self._get_leaf_style(node)\n            shape = f\"{node_id}[\u002F{node.name}\u002F]\"\n            self._lines.append(f\"    style {node_id} {style}\")\n\n        self._lines.append(f\"    {shape}\")\n\n        if parent_id:\n            connector = \"-->\" if node.node_type != NodeType.AND else \"==>\"\n            self._lines.append(f\"    {parent_id} {connector} {node_id}\")\n\n        for child in node.children:\n            self._export_node(child, node_id)\n\n        return node_id\n\n    def _get_leaf_style(self, node: AttackNode) -> str:\n        \"\"\"Get style based on attack attributes.\"\"\"\n        colors = {\n            Difficulty.TRIVIAL: \"fill:#ff6b6b\",  # Red - easy attack\n            Difficulty.LOW: \"fill:#ffa06b\",\n            Difficulty.MEDIUM: \"fill:#ffd93d\",\n            Difficulty.HIGH: \"fill:#6bcb77\",\n            Difficulty.EXPERT: \"fill:#4d96ff\",  # Blue - hard attack\n        }\n        color = colors.get(node.attributes.difficulty, \"fill:#gray\")\n        return color\n\n\nclass PlantUMLExporter:\n    \"\"\"Export attack trees to PlantUML format.\"\"\"\n\n    def __init__(self, tree: AttackTree):\n        self.tree = tree\n\n    def export(self) -> str:\n        \"\"\"Export tree to PlantUML.\"\"\"\n        lines = [\n            \"@startmindmap\",\n            f\"* {self.tree.name}\",\n        ]\n        self._export_node(self.tree.root, lines, 1)\n        lines.append(\"@endmindmap\")\n        return \"\\n\".join(lines)\n\n    def _export_node(self, node: AttackNode, lines: List[str], depth: int) -> None:\n        \"\"\"Recursively export nodes.\"\"\"\n        prefix = \"*\" * (depth + 1)\n\n        if node.node_type == NodeType.OR:\n            marker = \"[OR]\"\n        elif node.node_type == NodeType.AND:\n            marker = \"[AND]\"\n        else:\n            diff = node.attributes.difficulty.name\n            marker = f\"\u003C\u003C{diff}>>\"\n\n        lines.append(f\"{prefix} {marker} {node.name}\")\n\n        for child in node.children:\n            self._export_node(child, lines, depth + 1)\n```\n\n### Template 4: Attack Path Analysis\n\n```python\nfrom typing import Set, Tuple\n\nclass AttackPathAnalyzer:\n    \"\"\"Analyze attack paths and coverage.\"\"\"\n\n    def __init__(self, tree: AttackTree):\n        self.tree = tree\n\n    def get_all_paths(self) -> List[List[AttackNode]]:\n        \"\"\"Get all possible attack paths.\"\"\"\n        paths = []\n        self._collect_paths(self.tree.root, [], paths)\n        return paths\n\n    def _collect_paths(\n        self,\n        node: AttackNode,\n        current_path: List[AttackNode],\n        all_paths: List[List[AttackNode]]\n    ) -> None:\n        \"\"\"Recursively collect all paths.\"\"\"\n        current_path = current_path + [node]\n\n        if node.node_type == NodeType.LEAF:\n            all_paths.append(current_path)\n            return\n\n        if not node.children:\n            all_paths.append(current_path)\n            return\n\n        if node.node_type == NodeType.OR:\n            # Each child is a separate path\n            for child in node.children:\n                self._collect_paths(child, current_path, all_paths)\n        else:  # AND\n            # Must combine all children\n            child_paths = []\n            for child in node.children:\n                child_sub_paths = []\n                self._collect_paths(child, [], child_sub_paths)\n                child_paths.append(child_sub_paths)\n\n            # Combine paths from all AND children\n            combined = self._combine_and_paths(child_paths)\n            for combo in combined:\n                all_paths.append(current_path + combo)\n\n    def _combine_and_paths(\n        self,\n        child_paths: List[List[List[AttackNode]]]\n    ) -> List[List[AttackNode]]:\n        \"\"\"Combine paths from AND node children.\"\"\"\n        if not child_paths:\n            return [[]]\n\n        if len(child_paths) == 1:\n            return [path for paths in child_paths for path in paths]\n\n        # Cartesian product of all child path combinations\n        result = [[]]\n        for paths in child_paths:\n            new_result = []\n            for existing in result:\n                for path in paths:\n                    new_result.append(existing + path)\n            result = new_result\n        return result\n\n    def calculate_path_metrics(self, path: List[AttackNode]) -> Dict:\n        \"\"\"Calculate metrics for a specific path.\"\"\"\n        leaves = [n for n in path if n.node_type == NodeType.LEAF]\n\n        total_difficulty = sum(n.attributes.difficulty.value for n in leaves)\n        total_cost = sum(n.attributes.cost.value for n in leaves)\n        total_time = sum(n.attributes.time_hours for n in leaves)\n        max_detection = max((n.attributes.detection_risk.value for n in leaves), default=0)\n\n        return {\n            \"steps\": len(leaves),\n            \"total_difficulty\": total_difficulty,\n            \"avg_difficulty\": total_difficulty \u002F len(leaves) if leaves else 0,\n            \"total_cost\": total_cost,\n            \"total_time_hours\": total_time,\n            \"max_detection_risk\": max_detection,\n            \"requires_insider\": any(n.attributes.requires_insider for n in leaves),\n            \"requires_physical\": any(n.attributes.requires_physical for n in leaves),\n        }\n\n    def identify_critical_nodes(self) -> List[Tuple[AttackNode, int]]:\n        \"\"\"Find nodes that appear in the most paths.\"\"\"\n        paths = self.get_all_paths()\n        node_counts: Dict[str, Tuple[AttackNode, int]] = {}\n\n        for path in paths:\n            for node in path:\n                if node.id not in node_counts:\n                    node_counts[node.id] = (node, 0)\n                node_counts[node.id] = (node, node_counts[node.id][1] + 1)\n\n        return sorted(\n            node_counts.values(),\n            key=lambda x: x[1],\n            reverse=True\n        )\n\n    def coverage_analysis(self, mitigated_attacks: Set[str]) -> Dict:\n        \"\"\"Analyze how mitigations affect attack coverage.\"\"\"\n        all_paths = self.get_all_paths()\n        blocked_paths = []\n        open_paths = []\n\n        for path in all_paths:\n            path_attacks = {n.id for n in path if n.node_type == NodeType.LEAF}\n            if path_attacks & mitigated_attacks:\n                blocked_paths.append(path)\n            else:\n                open_paths.append(path)\n\n        return {\n            \"total_paths\": len(all_paths),\n            \"blocked_paths\": len(blocked_paths),\n            \"open_paths\": len(open_paths),\n            \"coverage_percentage\": len(blocked_paths) \u002F len(all_paths) * 100 if all_paths else 0,\n            \"open_path_details\": [\n                {\"path\": [n.name for n in p], \"metrics\": self.calculate_path_metrics(p)}\n                for p in open_paths[:5]  # Top 5 open paths\n            ]\n        }\n\n    def prioritize_mitigations(self) -> List[Dict]:\n        \"\"\"Prioritize mitigations by impact.\"\"\"\n        critical_nodes = self.identify_critical_nodes()\n        paths = self.get_all_paths()\n        total_paths = len(paths)\n\n        recommendations = []\n        for node, count in critical_nodes:\n            if node.node_type == NodeType.LEAF and node.mitigations:\n                recommendations.append({\n                    \"attack\": node.name,\n                    \"attack_id\": node.id,\n                    \"paths_blocked\": count,\n                    \"coverage_impact\": count \u002F total_paths * 100,\n                    \"difficulty\": node.attributes.difficulty.name,\n                    \"mitigations\": node.mitigations,\n                })\n\n        return sorted(recommendations, key=lambda x: x[\"coverage_impact\"], reverse=True)\n```\n\n## Best Practices\n\n### Do's\n- **Start with clear goals** - Define what attacker wants\n- **Be exhaustive** - Consider all attack vectors\n- **Attribute attacks** - Cost, skill, and detection\n- **Update regularly** - New threats emerge\n- **Validate with experts** - Red team review\n\n### Don'ts\n- **Don't oversimplify** - Real attacks are complex\n- **Don't ignore dependencies** - AND nodes matter\n- **Don't forget insider threats** - Not all attackers are external\n- **Don't skip mitigations** - Trees are for defense planning\n- **Don't make it static** - Threat landscape evolves\n\n## Resources\n\n- [Attack Trees by Bruce Schneier](https:\u002F\u002Fwww.schneier.com\u002Facademic\u002Farchives\u002F1999\u002F12\u002Fattack_trees.html)\n- [MITRE ATT&CK Framework](https:\u002F\u002Fattack.mitre.org\u002F)\n- [OWASP Attack Surface Analysis](https:\u002F\u002Fowasp.org\u002Fwww-community\u002Fcontrols\u002FAttack_Surface_Analysis_Cheat_Sheet)\n",{"name":5,"description":7},"main","7850740bd837adb32f0a109ab2af82482196c6f2","skills\u002F_collections\u002Fwshobson-agents\u002Fplugins\u002Fsecurity-scanning\u002Fskills\u002Fattack-tree-construction",1,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills","https:\u002F\u002Fzturnsgo.com","https:\u002F\u002Fgithub.com\u002Fshengdabai","https:\u002F\u002Fzturnsgo.com\u002F","AI × education creator — producer, not consumer. Taught 6,000+ learners; shipping learning tools & daily essays with Claude Code, practicing @xiaolai's way 🥋","2026-11-01 21:28:23",{"source":8,"skillName":5,"commands":49,"prompt":59,"zipAvailable":60},[50,53,56],{"tool":51,"command":52},"npx","npx skills add shengdabai\u002FTony-Claude-Code-Skills --skill attack-tree-construction",{"tool":54,"command":55},"bunx","bunx skills add shengdabai\u002FTony-Claude-Code-Skills --skill attack-tree-construction",{"tool":57,"command":58},"pnpm","pnpm dlx skills add shengdabai\u002FTony-Claude-Code-Skills --skill attack-tree-construction","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Fwshobson-agents\u002Fplugins\u002Fsecurity-scanning\u002Fskills\u002Fattack-tree-construction\u002FSKILL.md",true,[],[63,82,116,141,163,183],{"skillNo":64,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":74,"publishedAt":33},"01M70P17DAD4C1C47NPH6A96EM","xiaolai-methodology","以李笑来(Li Xiaolai)的思考方式、方法论与表达风格,为用户做全方位 1-on-1 教练指导,覆盖创业、赚钱、投资、学习、自学、读书写作、用 AI、以及人生心态与自我管理。当用户提到 \"李笑来\"、\"笑来\"、\"笑来老师\"、\"扮演李笑来\"、\"找笑来聊聊\"、\"笑来怎么看\"、\"xiaolai\"、\"把时间当作朋友\"、\"通往财富自由之路\"、\"定投改变命运\"、\"韭菜的自我修养\"、\"自学是门手艺\"、\"让时间陪你慢慢变富\"、\"七年就是一辈子\"、\"元认知\"、\"活在未来\"、\"复利\u002F长期主义\"、\"践行\"、\"痴迷改进\"、\"个人商业模式\u002F出售时间\"、\"睡后收入\"、\"定投\"、\"财富自由\"、\"操作系统升级\"、\"最少必要知识\"、\"北极星提示词\"、\"用 AI 该怎么学\u002F思考\" 等任一触发词,或当用户带着关于创业\u002F赚钱\u002F投资\u002F学习\u002F职业\u002F重大人生决策的困惑、希望被人用笑来式的「逻辑 + 大白话 + 类比 + 重新定义 + 践行导向」来点醒和指导时,自动进入李笑来教练模式。","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fxiaolai-methodology\u002FSKILL.md",[69],{"categoryNo":70,"categoryName":71,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000018","写作与文案","SCENARIO","使用场景",[75,76,77,78,79,80,81],"methodology","xiaolai","xiaolai methodology","朋友","投资","writing","收入",{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":96,"publishedAt":33},"01M70P13NB9YP7ACJR1S861CDS","zread","Produce and consume a wiki-style knowledge base for a code repository via the `zread` CLI and its on-disk output under `.\u002F.zread\u002Fwiki\u002F`. Use this skill whenever the user wants to understand, onboard onto, explore, summarize, map, or get an overview of an unfamiliar codebase; asks for architecture docs, a project wiki, a repo walkthrough, module\u002Fpackage explanations, or \"what does this repo do\"; wants to generate, regenerate, resume, browse, or serve code documentation locally; or mentions zread \u002F zread.ai directly. Also use it proactively before diving into a large unknown repo — if `.\u002F.zread\u002Fwiki\u002Fcurrent` exists, read the generated pages instead of crawling source file-by-file; if it doesn't, consider offering to run `zread generate`. The trigger is the intent (understand a codebase through generated docs), not the literal word \"zread\".","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fzread\u002FSKILL.md",[88,91],{"categoryNo":89,"categoryName":90,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":92,"categoryName":93,"taxonomyType":94,"taxonomyTypeDesc":95},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[84,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115],"knowledge","wiki","explore","walkthrough","project","get","knowledge base","run","generate","intent","cli","map","documentation","project wiki","disk","architecture","code","unknown","generated",{"skillNo":117,"name":118,"nameZh":6,"description":119,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":126,"publishedAt":33},"01M70P10S4SWMZQ8BJAFBFDRW3","youtube","Launch the YouTube Creator Agent to auto-generate videos.\nUse when: user types \u002Fyoutube, wants to create YouTube videos,\ngenerate video content, or upload to YouTube.\nKeywords: youtube, video, 视频, 创作视频, 发布视频","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube\u002FSKILL.md",[122,123],{"categoryNo":89,"categoryName":90,"taxonomyType":72,"taxonomyTypeDesc":73},{"categoryNo":124,"categoryName":125,"taxonomyType":94,"taxonomyTypeDesc":95},"01JBSEEDCAT000000000000036","内容创作者",[118,127,128,129,130,131,132,133,105,134,135,136,24,23,137,138,139,140],"user","content","视频","creator","generate video","videos","launch","video content","create","upload","auto","types","Video","创作",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":148,"publishedAt":33},"01M70P0YE95D8BACZCGV8BK90K","youtube-script-sync","Sync, update, or optimize Tony's GetNote knowledge base `Youtube视频逐字稿` by turning each parent recording or first-person idea note into an idempotent child note containing a directly recordable YouTube long-video or Shorts script. Use when the user says “更新\u002F同步\u002F优化 Youtube视频逐字稿知识库”, or says “更新\u002F同步\u002F优化该知识库” while this knowledge base is the active context.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube-script-sync\u002FSKILL.md",[147],{"categoryNo":89,"categoryName":90,"taxonomyType":72,"taxonomyTypeDesc":73},[149,150,118,151,152,139,153,154,155,156,157,158,159,160,103,161,24,23,97,162],"sync","script","youtube script sync","recording","shorts","first","base","person","update","active","child","optimize","idempotent","long",{"skillNo":164,"name":165,"nameZh":6,"description":166,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":167,"categories":168,"keywords":173,"publishedAt":33},"01M70P0WMV5XT0EEC0N445PW07","writing-skills","How to write SKILL.md files that trigger reliably and teach effectively. Use when creating, improving, or reviewing Claude Code skills.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fxiaolai\u002Fnlpm\u002Fskills\u002Fnlpm\u002Fwriting-skills\u002FSKILL.md",[169,170,171,172],{"categoryNo":70,"categoryName":71,"taxonomyType":72,"taxonomyTypeDesc":73},{"categoryNo":89,"categoryName":90,"taxonomyType":72,"taxonomyTypeDesc":73},{"categoryNo":92,"categoryName":93,"taxonomyType":94,"taxonomyTypeDesc":95},{"categoryNo":124,"categoryName":125,"taxonomyType":94,"taxonomyTypeDesc":95},[174,80,175,176,177,178,113,24,23,179,180,181,182],"writing skills","how","teach","write skill","write","claude code skills","files","how to","trigger",{"skillNo":184,"name":185,"nameZh":6,"description":186,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":187,"categories":188,"keywords":191,"publishedAt":33},"01M70P0SJFR4YVJQBGMHKGSKXT","writing-rules","How to write .claude\u002Frules\u002F files that Claude actually follows. Use when creating, improving, or reviewing project rules.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fxiaolai\u002Fnlpm\u002Fskills\u002Fnlpm\u002Fwriting-rules\u002FSKILL.md",[189,190],{"categoryNo":70,"categoryName":71,"taxonomyType":72,"taxonomyTypeDesc":73},{"categoryNo":124,"categoryName":125,"taxonomyType":94,"taxonomyTypeDesc":95},[192,80,193,101,194,180,24,175,178,23,181],"Rules","writing rules","project rules"]