Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implement automated incident response playbooks in Cortex XSOAR to orchestrate security workflows across SOC tools and reduce manual response time.
.claude/skills/implementing-soar-playbook-with-palo-alto-xsoar/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-18 | ✗→✓ | ▲ Improved | — | — |
| case-07 | ✗→✓ | ▲ Improved | — | — |
| case-08 | ✗→✓ | ▲ Improved | — | — |
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.
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| 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 |
yamlincident_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
yamlid: 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
!ParseEmailFiles entryid=${File.EntryID}
!rasterize url=${URL.Data} type=png!url url=${URL.Data}
!file file=${File.SHA256}
!ip ip=${IP.Address}
!domain domain=${Domain.Name}!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}!jira-create-issue summary="Phishing Incident - ${incident.id}" type="Incident" priority="High"
!servicenow-create-ticket short_description="Security Incident" urgency="2"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 positiveTrigger: 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 closeTrigger: 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 documentpython# 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()
| 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 |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +36 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.