soc operations

Implementing SOAR Playbook with Palo Alto XSOAR

Implement automated incident response playbooks in Cortex XSOAR to orchestrate security workflows across SOC tools and reduce manual response time.

automationcortexincident-responseorchestrationpalo-altoplaybooksoarxsoar
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Cortex XSOAR (formerly Demisto) is Palo Alto Networks' Security Orchestration, Automation, and Response platform. Playbooks are the core automation engine in XSOAR, enabling SOC teams to automate repetitive incident response tasks. XSOAR provides 900+ prebuilt integration packs, 87 common playbooks, and a visual drag-and-drop editor for building custom workflows. Organizations using SOAR automation reduce mean time to respond (MTTR) by 80% on average.

When to Use

  • When deploying or configuring implementing soar playbook with palo alto xsoar capabilities in your environment
  • When establishing security controls aligned to compliance requirements
  • When building or improving security architecture for this domain
  • When conducting security assessments that require this implementation

Prerequisites

  • Cortex XSOAR deployed (version 8.x or later, or XSOAR hosted)
  • Administrative access for playbook creation
  • Integration packs installed for relevant security tools
  • Incident types and layouts configured
  • API access to external tools (SIEM, EDR, TI platforms, ticketing)

Playbook Architecture

XSOAR Component Hierarchy

Incident Type (e.g., Phishing)
    |
    v
Incident Layout (UI display configuration)
    |
    v
Pre-Processing Rules (auto-classification, deduplication)
    |
    v
Playbook (automation logic)
    |-- Sub-Playbooks (modular reusable workflows)
    |-- Tasks (individual automation steps)
    |-- Conditional Tasks (decision branches)
    |-- Scripts (custom Python/JavaScript)
    |-- Integrations (external tool commands)
    |
    v
War Room (investigation timeline)
    |
    v
Closing Report

Playbook Task Types

Task Type Purpose Example
Standard Execute a command !ip ip=8.8.8.8
Conditional Branch logic If severity > high, escalate
Manual Require analyst input Approve containment action
Section Header Organize workflow "Enrichment Phase"
Data Collection Gather external data Ask user for additional details
Timer Wait for condition/time Wait 5 minutes then check

Building a Phishing Response Playbook

Step 1: Define Incident Type

incident_type: Phishing
playbook: Phishing Investigation - Full
severity_mapping:
  - condition: email contains executable attachment
    severity: high
  - condition: email from external domain with link
    severity: medium
  - condition: email reported by user
    severity: low
layout: Phishing Layout
sla: 60 minutes

Step 2: Playbook YAML Structure

id: phishing-investigation-full
version: -1
name: Phishing Investigation - Full
description: Automated phishing email investigation with enrichment, analysis, and response
starttaskid: "0"
tasks:
  "0":
    id: "0"
    taskid: start
    type: start
    nexttasks:
      '#none#':
      - "1"
  "1":
    id: "1"
    taskid: extract-indicators
    type: regular
    task:
      name: Extract Indicators from Email
      script: ParseEmailFiles
    nexttasks:
      '#none#':
      - "2"
      - "3"
      - "4"
  "2":
    id: "2"
    taskid: enrich-urls
    type: playbook
    task:
      name: URL Enrichment
      playbookName: URL Enrichment - Generic v2
  "3":
    id: "3"
    taskid: enrich-files
    type: playbook
    task:
      name: File Enrichment
      playbookName: File Enrichment - Generic v2
  "4":
    id: "4"
    taskid: enrich-ips
    type: playbook
    task:
      name: IP Enrichment
      playbookName: IP Enrichment - Generic v2
  "5":
    id: "5"
    taskid: determine-verdict
    type: condition
    task:
      name: Is Email Malicious?
    conditions:
      - label: "yes"
        condition:
          - - operator: isEqualString
              left: DBotScore.Score
              right: "3"
      - label: "no"
    nexttasks:
      "yes":
      - "6"
      "no":
      - "9"
  "6":
    id: "6"
    taskid: block-sender
    type: regular
    task:
      name: Block Sender Domain
      script: '|||o365-mail-block-sender'
    scriptarguments:
      sender_address: ${incident.emailfrom}
  "7":
    id: "7"
    taskid: search-mailboxes
    type: regular
    task:
      name: Search and Delete from All Mailboxes
      script: '|||o365-mail-purge-compliance-search'
    scriptarguments:
      query: "from:${incident.emailfrom} subject:${incident.emailsubject}"
  "8":
    id: "8"
    taskid: notify-user
    type: regular
    task:
      name: Notify Reporting User
      script: '|||send-mail'
    scriptarguments:
      to: ${incident.reporter}
      subject: "Phishing Report Confirmed - Action Taken"
      body: "The email you reported has been confirmed as malicious and removed."
  "9":
    id: "9"
    taskid: close-incident
    type: regular
    task:
      name: Close Incident
      script: closeInvestigation

Step 3: Integration Commands

Email Analysis

!ParseEmailFiles entryid=${File.EntryID}
!rasterize url=${URL.Data} type=png

Threat Intelligence Enrichment

!url url=${URL.Data}
!file file=${File.SHA256}
!ip ip=${IP.Address}
!domain domain=${Domain.Name}

Containment Actions

!o365-mail-block-sender sender=${incident.emailfrom}
!o365-mail-purge-compliance-search query="from:${incident.emailfrom}"
!pan-os-block-ip ip=${IP.Address} log_forwarding="default"
!cortex-xdr-isolate-endpoint endpoint_id=${Endpoint.ID}

Ticketing Integration

!jira-create-issue summary="Phishing Incident - ${incident.id}" type="Incident" priority="High"
!servicenow-create-ticket short_description="Security Incident" urgency="2"

Common SOC Playbook Templates

1. Malware Investigation Playbook

Trigger: Malware alert from EDR
Steps:
  1. Extract file hash, process details, host info
  2. Enrich hash via VirusTotal, Hybrid Analysis
  3. Check if file is on allowlist
  4. If malicious:
     a. Isolate endpoint via EDR
     b. Block hash on all endpoints
     c. Search for hash across environment
     d. Create incident ticket
  5. If clean: Close as false positive

2. Account Compromise Playbook

Trigger: Impossible travel or suspicious login alert
Steps:
  1. Get user details from Active Directory
  2. Get login history for past 30 days
  3. Check for impossible travel (geo-distance vs time)
  4. Check for known VPN/proxy IP
  5. If compromised:
     a. Disable AD account
     b. Revoke all OAuth tokens
     c. Reset MFA
     d. Notify user's manager
     e. Search for lateral movement
  6. If false positive: Document and close

3. DDoS Mitigation Playbook

Trigger: Network anomaly alert
Steps:
  1. Verify traffic spike from network monitoring
  2. Identify source IPs and geolocation
  3. Check if source IPs are known botnets
  4. Implement rate limiting on WAF
  5. If sustained attack:
     a. Enable upstream DDoS protection
     b. Activate CDN scrubbing
     c. Notify ISP if needed
  6. Monitor and document

Custom XSOAR Scripts

Python Automation Script Example

# XSOAR Automation Script: CalculateRiskScore
def calculate_risk_score():
    """Calculate composite risk score for an incident."""
    severity = demisto.incident().get('severity', 0)
    indicator_count = len(demisto.get(demisto.context(), 'DBotScore', []))
    malicious_count = len([
        i for i in demisto.get(demisto.context(), 'DBotScore', [])
        if i.get('Score', 0) == 3
    ])
 
    base_score = severity * 20
    indicator_boost = min(indicator_count * 5, 25)
    malicious_boost = malicious_count * 15
 
    risk_score = min(100, base_score + indicator_boost + malicious_boost)
 
    return_results(CommandResults(
        outputs_prefix='RiskScore',
        outputs={'Score': risk_score, 'Level': 'Critical' if risk_score > 80 else 'High' if risk_score > 60 else 'Medium'},
        readable_output=f'Risk Score: {risk_score}/100'
    ))
 
calculate_risk_score()

Playbook Performance Metrics

Metric Before SOAR After SOAR Improvement
Phishing MTTR 45 min 5 min 89% reduction
Malware MTTR 60 min 8 min 87% reduction
Account Compromise MTTR 30 min 4 min 87% reduction
Alerts Handled per Shift 50 200+ 300% increase
False Positive Handling 10 min 30 sec 95% reduction

References

Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md4.1 KB

API Reference: Palo Alto Cortex XSOAR SOAR Playbook

Libraries Used

Library Purpose
requests HTTP client for XSOAR REST API
json Parse incident and playbook payloads
os Read XSOAR_URL and XSOAR_API_KEY environment variables

Installation

pip install requests

Authentication

import requests
import os
 
XSOAR_URL = os.environ["XSOAR_URL"]  # e.g., "https://xsoar.example.com"
headers = {
    "Authorization": os.environ["XSOAR_API_KEY"],
    "Content-Type": "application/json",
    "Accept": "application/json",
}

REST API Endpoints

Method Endpoint Description
POST /incident Create a new incident
POST /incident/search Search incidents
GET /incident/{id} Get incident details
POST /incident/close Close an incident
POST /playbook/search Search playbooks
GET /playbook/{id} Get playbook details
POST /entry/execute/{playbook} Run a playbook on an incident
POST /automation/search Search automation scripts
POST /automation/execute Execute an automation command
GET /settings/integration/search List integrations
POST /indicators/search Search indicators (IOCs)
POST /indicators Create indicators
GET /health System health check
GET /user Get current user info

Core Operations

Create an Incident

incident = {
    "name": "Phishing Alert - Suspicious Email",
    "type": "Phishing",
    "severity": 3,  # 0=Unknown, 1=Low, 2=Medium, 3=High, 4=Critical
    "labels": [
        {"type": "Email/from", "value": "attacker@evil.com"},
        {"type": "Email/subject", "value": "Urgent: Verify Account"},
    ],
    "customFields": {
        "sourceemail": "attacker@evil.com",
        "reportedby": "soc-analyst-1",
    },
}
resp = requests.post(
    f"{XSOAR_URL}/incident",
    headers=headers,
    json=incident,
    timeout=30,
)
incident_id = resp.json()["id"]

Search Incidents

search = {
    "filter": {
        "query": "type:Phishing AND severity:>=3",
        "period": {"fromValue": "7 days ago"},
    },
    "page": 0,
    "size": 50,
}
resp = requests.post(
    f"{XSOAR_URL}/incident/search",
    headers=headers,
    json=search,
    timeout=30,
)
incidents = resp.json().get("data", [])

Execute a Playbook on an Incident

resp = requests.post(
    f"{XSOAR_URL}/entry/execute/{playbook_name}",
    headers=headers,
    json={"investigationId": incident_id},
    timeout=30,
)

Search Playbooks

resp = requests.post(
    f"{XSOAR_URL}/playbook/search",
    headers=headers,
    json={
        "query": "name:*phishing*",
        "page": 0,
        "size": 20,
    },
    timeout=30,
)
playbooks = resp.json().get("playbooks", [])
for pb in playbooks:
    print(f"{pb['name']} — tasks: {len(pb.get('tasks', {}))}")

Run an Automation Command

resp = requests.post(
    f"{XSOAR_URL}/automation/execute",
    headers=headers,
    json={
        "script": "!ip ip=8.8.8.8",
        "investigationId": incident_id,
    },
    timeout=60,
)

Search Indicators (IOCs)

resp = requests.post(
    f"{XSOAR_URL}/indicators/search",
    headers=headers,
    json={
        "query": "type:IP AND verdict:malicious",
        "size": 100,
    },
    timeout=30,
)
indicators = resp.json().get("iocObjects", [])

Check Integration Health

resp = requests.get(
    f"{XSOAR_URL}/settings/integration/search",
    headers=headers,
    timeout=30,
)
integrations = resp.json().get("instances", [])
for inst in integrations:
    status = "healthy" if inst.get("enabled") else "disabled"
    print(f"{inst['name']} — brand: {inst['brand']}{status}")

Output Format

{
  "id": "12345",
  "name": "Phishing Alert - Suspicious Email",
  "type": "Phishing",
  "severity": 3,
  "status": 1,
  "created": "2025-01-15T10:30:00Z",
  "phase": "Triage",
  "playbooks": ["Phishing Investigation - Generic v2"],
  "labels": [
    {"type": "Email/from", "value": "attacker@evil.com"}
  ]
}
standards.md1.7 KB

Standards and References - SOAR Playbook with XSOAR

SOAR Industry Standards

Gartner SOAR Definition

Security Orchestration, Automation and Response (SOAR) combines:

  • Security Orchestration and Automation (SOA)
  • Security Incident Response Platforms (SIRP)
  • Threat Intelligence Platforms (TIP)

NIST SP 800-61 Rev 2 - Incident Handling

SOAR playbooks implement the NIST incident response lifecycle:

  1. Preparation
  2. Detection and Analysis
  3. Containment, Eradication, and Recovery
  4. Post-Incident Activity

MITRE ATT&CK for Response

Playbooks should map containment actions to specific MITRE ATT&CK techniques being mitigated.

XSOAR Architecture Standards

Content Pack Structure

content-pack/
  Integrations/
    integration-name/
      integration-name.py
      integration-name.yml
      integration-name_test.py
  Playbooks/
    playbook-name.yml
  Scripts/
    script-name/
      script-name.py
      script-name.yml
  IncidentTypes/
  Layouts/
  Classifiers/

Playbook Design Principles

  1. Modular sub-playbooks for reusability
  2. Error handling on every integration command
  3. Manual review gates for destructive actions
  4. SLA timers for response targets
  5. Closing report generation for documentation

Integration Best Practices

Integration Category Examples Usage
SIEM Splunk, Sentinel, QRadar Alert ingestion, log queries
EDR CrowdStrike, Defender, SentinelOne Endpoint isolation, hash blocking
Email Security O365, Proofpoint, Mimecast Email analysis, sender blocking
Threat Intelligence VirusTotal, MISP, OTX IOC enrichment
Ticketing Jira, ServiceNow Incident tracking
Communication Slack, Teams, PagerDuty Notifications, approvals
workflows.md2.0 KB

Workflows - SOAR Playbook with XSOAR

Playbook Development Lifecycle

1. Identify Manual Process
   - Document current analyst workflow
   - Measure time per step
   |
   v
2. Design Playbook Logic
   - Map decision points
   - Identify automation candidates
   - Define manual review gates
   |
   v
3. Build in XSOAR
   - Create playbook in visual editor
   - Configure integration commands
   - Add conditional branches
   - Write custom scripts if needed
   |
   v
4. Test with Sample Data
   - Create test incidents
   - Verify each task executes correctly
   - Test error handling paths
   |
   v
5. Pilot in Production
   - Run on subset of incidents
   - Compare automated vs manual results
   - Gather analyst feedback
   |
   v
6. Full Deployment
   - Enable for all matching incidents
   - Monitor playbook performance
   - Track MTTR improvements
   |
   v
7. Continuous Improvement
   - Review failed tasks monthly
   - Update integrations as needed
   - Add new sub-playbooks

Incident Lifecycle in XSOAR

Alert Ingestion (SIEM/EDR/Email)
    |
    v
Pre-Processing (Classification, Deduplication)
    |
    v
Incident Created (Type, Severity, Owner assigned)
    |
    v
Playbook Triggered Automatically
    |
    +-- Enrichment Phase (parallel)
    |   |-- IP/Domain/Hash lookup
    |   |-- User/Asset lookup
    |   |-- TI feed correlation
    |
    +-- Analysis Phase
    |   |-- Verdict determination
    |   |-- Risk scoring
    |
    +-- Response Phase
    |   |-- Containment actions (auto or manual approval)
    |   |-- Eradication steps
    |   |-- Recovery procedures
    |
    +-- Documentation Phase
    |   |-- War room timeline
    |   |-- Closing report
    |   |-- Ticket update
    |
    v
Incident Closed

ROI Measurement Workflow

Before SOAR:
  Count manual hours per incident type per month
 
After SOAR:
  Measure automated handling time
  Calculate: Saved Hours = Manual Hours - Automated Hours
  Calculate: ROI = (Saved Hours * Analyst Hourly Cost) / SOAR License Cost

Scripts 2

agent.py7.3 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Cortex XSOAR playbook management agent.

Interfaces with the Cortex XSOAR (Demisto) API to manage and audit
security playbooks, automation scripts, incidents, and integrations.
Supports listing playbooks, checking incident statistics, and
verifying integration health.
"""
import argparse
import json
import os
import sys
from datetime import datetime, timezone

try:
    import requests
except ImportError:
    print("[!] 'requests' required: pip install requests", file=sys.stderr)
    sys.exit(1)


def get_xsoar_config():
    """Return XSOAR server URL and API key."""
    server = os.environ.get("XSOAR_URL", "").rstrip("/")
    api_key = os.environ.get("XSOAR_API_KEY", "")
    if not server or not api_key:
        print("[!] Set XSOAR_URL and XSOAR_API_KEY env vars", file=sys.stderr)
        sys.exit(1)
    return server, api_key


def xsoar_api(server, api_key, endpoint, method="POST", data=None):
    """Make authenticated XSOAR API call."""
    url = f"{server}{endpoint}"
    headers = {"Authorization": api_key, "Content-Type": "application/json",
               "Accept": "application/json"}
    if method == "GET":
        resp = requests.get(url, headers=headers,
                            verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    else:
        resp = requests.post(url, headers=headers, json=data or {},
                             verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    resp.raise_for_status()
    return resp.json()


def list_playbooks(server, api_key, query=""):
    """List all playbooks."""
    print("[*] Fetching playbooks...")
    data = {"query": query, "page": 0, "size": 500}
    result = xsoar_api(server, api_key, "/playbook/search", data=data)
    playbooks = result.get("playbooks", [])
    print(f"[+] Found {len(playbooks)} playbooks")
    return [{
        "id": pb.get("id", ""),
        "name": pb.get("name", ""),
        "version": pb.get("version", 0),
        "deprecated": pb.get("deprecated", False),
        "hidden": pb.get("hidden", False),
        "system": pb.get("system", False),
        "modified": pb.get("modified", ""),
    } for pb in playbooks]


def get_incident_stats(server, api_key, days=30):
    """Get incident statistics."""
    print(f"[*] Fetching incident statistics (last {days}d)...")
    data = {"size": 0, "filter": {"period": {"by": "day", "fromValue": days}}}
    result = xsoar_api(server, api_key, "/incidents/search", data=data)
    total = result.get("total", 0)
    print(f"[+] {total} incidents in last {days} days")

    # Get status breakdown
    statuses = {}
    data_with_agg = {"size": 0, "filter": {"period": {"by": "day", "fromValue": days}},
                     "aggregations": [{"field": "status", "type": "terms"}]}
    try:
        agg_result = xsoar_api(server, api_key, "/incidents/search", data=data_with_agg)
        for bucket in agg_result.get("aggregations", {}).get("status", {}).get("buckets", []):
            statuses[bucket.get("key", "unknown")] = bucket.get("doc_count", 0)
    except (requests.RequestException, KeyError):
        pass

    return {"total": total, "period_days": days, "by_status": statuses}


def list_integrations(server, api_key):
    """List configured integrations and their health."""
    print("[*] Fetching integrations...")
    result = xsoar_api(server, api_key, "/settings/integration/search",
                       data={"size": 500})
    instances = result.get("instances", [])
    integrations = []
    for inst in instances:
        integrations.append({
            "name": inst.get("name", ""),
            "brand": inst.get("brand", ""),
            "enabled": inst.get("enabled", ""),
            "is_long_running": inst.get("isLongRunning", False),
            "configured": inst.get("configurationStatus", ""),
        })
    print(f"[+] Found {len(integrations)} integration instances")
    return integrations


def audit_playbook_health(playbooks, integrations):
    """Audit playbooks for common issues."""
    findings = []
    deprecated = [pb for pb in playbooks if pb.get("deprecated")]
    if deprecated:
        findings.append({
            "check": "Deprecated playbooks in use",
            "severity": "MEDIUM",
            "count": len(deprecated),
            "detail": ", ".join(pb["name"] for pb in deprecated[:5]),
        })

    disabled_integrations = [i for i in integrations if i.get("enabled") == "false"]
    if disabled_integrations:
        findings.append({
            "check": "Disabled integrations",
            "severity": "HIGH",
            "count": len(disabled_integrations),
            "detail": ", ".join(i["name"] for i in disabled_integrations[:5]),
        })

    return findings


def format_summary(playbooks, incident_stats, integrations, findings):
    """Print XSOAR audit summary."""
    print(f"\n{'='*60}")
    print(f"  Cortex XSOAR Playbook Audit Report")
    print(f"{'='*60}")
    print(f"  Playbooks    : {len(playbooks)}")
    print(f"  Integrations : {len(integrations)}")
    print(f"  Incidents    : {incident_stats.get('total', 0)} (last {incident_stats.get('period_days', 30)}d)")
    print(f"  Findings     : {len(findings)}")

    if incident_stats.get("by_status"):
        print(f"\n  Incidents by Status:")
        for status, count in incident_stats["by_status"].items():
            print(f"    {status:15s}: {count}")

    enabled_count = sum(1 for i in integrations if i.get("enabled") != "false")
    print(f"\n  Integrations: {enabled_count} enabled, {len(integrations) - enabled_count} disabled")

    severity_counts = {}
    for f in findings:
        sev = f.get("severity", "INFO")
        severity_counts[sev] = severity_counts.get(sev, 0) + 1
    return severity_counts


def main():
    parser = argparse.ArgumentParser(description="Cortex XSOAR playbook audit agent")
    parser.add_argument("--url", help="XSOAR URL (or XSOAR_URL env)")
    parser.add_argument("--api-key", help="API key (or XSOAR_API_KEY env)")
    parser.add_argument("--days", type=int, default=30, help="Incident stats period")
    parser.add_argument("--output", "-o", help="Output JSON report")
    parser.add_argument("--verbose", "-v", action="store_true")
    args = parser.parse_args()

    if args.url:
        os.environ["XSOAR_URL"] = args.url
    if args.api_key:
        os.environ["XSOAR_API_KEY"] = args.api_key

    server, api_key = get_xsoar_config()

    playbooks = list_playbooks(server, api_key)
    incident_stats = get_incident_stats(server, api_key, args.days)
    integrations = list_integrations(server, api_key)
    findings = audit_playbook_health(playbooks, integrations)

    severity_counts = format_summary(playbooks, incident_stats, integrations, findings)

    report = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "tool": "Cortex XSOAR Audit",
        "playbooks": playbooks,
        "incident_stats": incident_stats,
        "integrations": integrations,
        "findings": findings,
        "severity_counts": severity_counts,
    }

    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2)
        print(f"\n[+] Report saved to {args.output}")
    elif args.verbose:
        print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
process.py9.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
XSOAR Playbook Builder and Validator

Generates XSOAR-compatible playbook YAML structures,
validates playbook logic, and tracks automation metrics.
"""

import json
import yaml
from datetime import datetime
from typing import Optional


class PlaybookTask:
    """Represents a single task in an XSOAR playbook."""

    def __init__(
        self,
        task_id: str,
        name: str,
        task_type: str = "regular",
        script: Optional[str] = None,
        playbook_name: Optional[str] = None,
        conditions: Optional[list] = None,
        next_tasks: Optional[dict] = None,
        script_arguments: Optional[dict] = None,
    ):
        self.task_id = task_id
        self.name = name
        self.task_type = task_type  # start, regular, condition, playbook, manual, title
        self.script = script
        self.playbook_name = playbook_name
        self.conditions = conditions or []
        self.next_tasks = next_tasks or {}
        self.script_arguments = script_arguments or {}

    def to_dict(self) -> dict:
        task = {
            "id": self.task_id,
            "taskid": self.task_id,
            "type": self.task_type,
            "task": {"name": self.name},
            "nexttasks": self.next_tasks,
        }
        if self.script:
            task["task"]["script"] = self.script
        if self.playbook_name:
            task["task"]["playbookName"] = self.playbook_name
        if self.conditions:
            task["conditions"] = self.conditions
        if self.script_arguments:
            task["scriptarguments"] = self.script_arguments
        return task


class XSOARPlaybook:
    """Represents a complete XSOAR playbook."""

    def __init__(self, name: str, description: str, incident_type: str):
        self.name = name
        self.description = description
        self.incident_type = incident_type
        self.tasks = {}
        self.start_task_id = "0"
        self.version = -1

    def add_task(self, task: PlaybookTask):
        self.tasks[task.task_id] = task

    def validate(self) -> dict:
        """Validate playbook structure and logic."""
        issues = []

        # Check start task exists
        if self.start_task_id not in self.tasks:
            issues.append("ERROR: Start task not found")

        # Check all referenced next tasks exist
        for task_id, task in self.tasks.items():
            for label, next_ids in task.next_tasks.items():
                for next_id in next_ids:
                    if next_id not in self.tasks:
                        issues.append(f"ERROR: Task {task_id} references non-existent task {next_id}")

        # Check for orphaned tasks (not reachable from start)
        reachable = set()
        queue = [self.start_task_id]
        while queue:
            current = queue.pop(0)
            if current in reachable:
                continue
            reachable.add(current)
            if current in self.tasks:
                for next_ids in self.tasks[current].next_tasks.values():
                    queue.extend(next_ids)

        orphaned = set(self.tasks.keys()) - reachable
        for orphan in orphaned:
            issues.append(f"WARNING: Task {orphan} ({self.tasks[orphan].name}) is not reachable")

        # Check conditional tasks have conditions
        for task_id, task in self.tasks.items():
            if task.task_type == "condition" and not task.conditions:
                issues.append(f"WARNING: Conditional task {task_id} has no conditions defined")

        # Check for manual review gates before destructive actions
        destructive_keywords = ["isolate", "block", "delete", "disable", "purge", "quarantine"]
        for task_id, task in self.tasks.items():
            if task.script and any(kw in task.script.lower() for kw in destructive_keywords):
                # Check if preceding task is manual
                has_manual_gate = False
                for other_id, other_task in self.tasks.items():
                    for next_ids in other_task.next_tasks.values():
                        if task_id in next_ids and other_task.task_type == "manual":
                            has_manual_gate = True
                if not has_manual_gate:
                    issues.append(
                        f"INFO: Destructive task {task_id} ({task.name}) "
                        f"has no manual approval gate"
                    )

        return {
            "playbook_name": self.name,
            "valid": not any(i.startswith("ERROR") for i in issues),
            "total_tasks": len(self.tasks),
            "reachable_tasks": len(reachable),
            "orphaned_tasks": len(orphaned),
            "issues": issues,
        }

    def to_yaml(self) -> str:
        playbook_dict = {
            "id": self.name.lower().replace(" ", "-"),
            "version": self.version,
            "name": self.name,
            "description": self.description,
            "starttaskid": self.start_task_id,
            "tasks": {tid: t.to_dict() for tid, t in self.tasks.items()},
        }
        return yaml.dump(playbook_dict, default_flow_style=False, sort_keys=False)


class SOARMetrics:
    """Track SOAR playbook performance metrics."""

    def __init__(self):
        self.executions = []

    def add_execution(
        self,
        playbook_name: str,
        incident_type: str,
        duration_seconds: int,
        manual_duration_seconds: int,
        tasks_automated: int,
        tasks_manual: int,
        success: bool,
    ):
        self.executions.append({
            "playbook_name": playbook_name,
            "incident_type": incident_type,
            "duration_seconds": duration_seconds,
            "manual_duration_seconds": manual_duration_seconds,
            "tasks_automated": tasks_automated,
            "tasks_manual": tasks_manual,
            "success": success,
            "timestamp": datetime.utcnow().isoformat(),
        })

    def calculate_roi(self, analyst_hourly_rate: float = 75.0) -> dict:
        total_manual_time = sum(e["manual_duration_seconds"] for e in self.executions)
        total_automated_time = sum(e["duration_seconds"] for e in self.executions)
        saved_seconds = total_manual_time - total_automated_time
        saved_hours = saved_seconds / 3600

        return {
            "total_executions": len(self.executions),
            "total_manual_time_hours": round(total_manual_time / 3600, 1),
            "total_automated_time_hours": round(total_automated_time / 3600, 1),
            "time_saved_hours": round(saved_hours, 1),
            "cost_savings": round(saved_hours * analyst_hourly_rate, 2),
            "automation_rate": round(
                sum(e["tasks_automated"] for e in self.executions)
                / max(1, sum(e["tasks_automated"] + e["tasks_manual"] for e in self.executions))
                * 100, 1
            ),
            "success_rate": round(
                sum(1 for e in self.executions if e["success"]) / max(1, len(self.executions)) * 100, 1
            ),
        }


def build_phishing_playbook() -> XSOARPlaybook:
    """Build a sample phishing investigation playbook."""
    pb = XSOARPlaybook(
        "Phishing Investigation",
        "Automated phishing email investigation with enrichment and response",
        "Phishing",
    )

    pb.add_task(PlaybookTask("0", "Start", "start", next_tasks={"#none#": ["1"]}))
    pb.add_task(PlaybookTask("1", "Extract Indicators from Email", "regular",
                             script="ParseEmailFiles", next_tasks={"#none#": ["2", "3", "4"]}))
    pb.add_task(PlaybookTask("2", "URL Enrichment", "playbook",
                             playbook_name="URL Enrichment - Generic v2", next_tasks={"#none#": ["5"]}))
    pb.add_task(PlaybookTask("3", "File Enrichment", "playbook",
                             playbook_name="File Enrichment - Generic v2", next_tasks={"#none#": ["5"]}))
    pb.add_task(PlaybookTask("4", "IP Enrichment", "playbook",
                             playbook_name="IP Enrichment - Generic v2", next_tasks={"#none#": ["5"]}))
    pb.add_task(PlaybookTask("5", "Is Email Malicious?", "condition",
                             conditions=[{"label": "yes", "operator": "isEqualString", "left": "DBotScore.Score", "right": "3"}],
                             next_tasks={"yes": ["6"], "no": ["9"]}))
    pb.add_task(PlaybookTask("6", "Approve Containment", "manual", next_tasks={"#none#": ["7"]}))
    pb.add_task(PlaybookTask("7", "Block Sender and Purge Emails", "regular",
                             script="o365-mail-block-sender", next_tasks={"#none#": ["8"]}))
    pb.add_task(PlaybookTask("8", "Notify User", "regular",
                             script="send-mail", next_tasks={"#none#": ["9"]}))
    pb.add_task(PlaybookTask("9", "Close Incident", "regular", script="closeInvestigation"))

    return pb


if __name__ == "__main__":
    playbook = build_phishing_playbook()

    print("=" * 70)
    print("XSOAR PLAYBOOK VALIDATOR")
    print("=" * 70)

    validation = playbook.validate()
    print(f"\nPlaybook: {validation['playbook_name']}")
    print(f"Valid: {validation['valid']}")
    print(f"Total Tasks: {validation['total_tasks']}")
    print(f"Reachable Tasks: {validation['reachable_tasks']}")
    for issue in validation["issues"]:
        print(f"  {issue}")

    print(f"\n{'=' * 70}")
    print("GENERATED PLAYBOOK YAML")
    print("=" * 70)
    print(playbook.to_yaml())

    # Simulate metrics
    metrics = SOARMetrics()
    metrics.add_execution("Phishing Investigation", "Phishing", 300, 2700, 8, 1, True)
    metrics.add_execution("Phishing Investigation", "Phishing", 240, 2700, 8, 1, True)
    metrics.add_execution("Phishing Investigation", "Phishing", 360, 2700, 7, 2, True)
    metrics.add_execution("Phishing Investigation", "Phishing", 280, 2700, 8, 1, False)

    print(f"\n{'=' * 70}")
    print("SOAR ROI METRICS")
    print("=" * 70)
    roi = metrics.calculate_roi()
    for key, value in roi.items():
        print(f"  {key}: {value}")

Assets 1

template.mdtext/markdown · 1.4 KB
Keep exploring