T Techclick ← All lessons
Palo Alto · Cortex XSOAR · Interactive lesson

XSOAR playbooks ingest then automate

Ticket: INC-4821 is Closed / False Positive, but the WildFire task never returned a verdict. Closed is a field. The playbook is a graph. An integration fetches an event; a classifier picks the incident type; a mapper fills fields; that type’s default playbook runs. Tasks write Context (JSON the next task reads) and the War Room (the audit trail). Containment is a manual gate, not a default edge. Lab: mailbox phish@lab.techclick.in, URL https://203.0.113.80/owa-login, playbook TC-Phish-Lab.

16 min read · L2 primary · Quiz at end

After this page you can

Lessons · Cortex series · XSOAR playbooks

This page vs XDR and XSIAM

This lesson is Cortex XSOAR: incident types, classifiers, playbooks, War Room. Cortex XDR is the telemetry and causality engine that often feeds XSOAR. Cortex XSIAM renamed many of the same objects to issues — do not mix the menus.

Cortex XDR architecture · Xpanse attack surface

Hero · mailbox and SIEM feed XSOAR, War Room closes
Mailbox and SIEM feeding an XSOAR orchestrator cube, then a War Room close panel
Mood, not a wiring diagram. Exact path is in the SVG: Graph Mail fetch → classifier Phishing → mapper fills Email From / Subject / URL → playbook TC-Phish-Lab → War Room entries → close. The artwork checkmark is not a verdict.
Quick answer

An integration fetches events. A classifier (or the instance default type) sets the incident type. A mapper copies rawJSON into incident fields; leftovers are labels. Pre-process may drop or link duplicates. The type’s default playbook runs if “Run playbook automatically” is on. Tasks write Context for the next hop and the War Room for the audit. Enrichment can be automatic. Isolate / block / mailbox purge wait on a manual or conditional task. Proof is the War Room task trail plus Context scores — Closed is just a field.

Why Closed is not a verdict

The day-one ticket is always the same: “The playbook finished, so the case is done.” Wrong. A playbook finishes when it reaches an end task. That can happen because enrichment succeeded, because a condition was empty, or because nobody wired an error branch. Closed means someone — or !closeInvestigation — wrote a close reason. It does not mean WildFire returned malicious, or that the URL was detonated at all.

Three silent-wrong states look identical in the incident list (status Closed):

Do not debug the playbook first

Start at ingest. If Classification & Mapping shows the event as Unclassified, the default playbook on the integration instance is what ran — not Phishing Investigation. War Room of INC-4821 will show which playbook name actually executed.

Four objects: integration, type, playbook, War Room

An integration instance is the connector: fetch incidents, run commands, optionally mirror. Fetch is a checkbox on the instance. Commands (!url, !wildfire-upload, !setIncident) are what playbook tasks and the War Room CLI actually call.

An incident type owns the default playbook, whether that playbook runs on ingest, auto-extract mode (None / Inline / Out of band), SLA, layout, and the post-process script. Classifier output is a type name. Type is not a playbook.

Path · ingest, classify, playbook, close
Four glass panels labeled Ingest, Classify, Playbook, Close
Feel of the order. Exact XSOAR sequence — classifier then mapper then pre-process then type default playbook — is in the SVG below. Classify is a type picker, not an AI diamond.

Integration

Marketplace pack → Settings → Integrations → Add instance. Lab: Microsoft Graph Mail graph_phish_in, Fetches incidents on, mailbox phish@lab.techclick.in.

Classifier / mapper

Classifier = incident type from a rawJSON key. Mapper = fields. Unmapped attributes → incident.labels. Classifier overrides the instance default type.

Playbook

Graph of standard (script/command), conditional, data-collection, and manual tasks. Inputs/outputs ride Context. Sub-playbooks are tasks with “Skip if unavailable.”

War Room vs Context

War Room is the journal: commands, notes, evidence, errors. Context is the JSON memory the next task reads. Quiet Mode still logs errors; it hides I/O noise.

Say this out loud

The integration fetches. The classifier names the type. The mapper fills fields. The type’s default playbook runs. Tasks write Context and the War Room. Close is a task, not a side effect of enrichment.

Incident lifecycle — ingest then automate

Official order: plan fields/types/layouts → configure integrations → classification and mapping → pre-processing → incident created → playbook (on create or manual) → post-processing on close. Playbooks also run when you launch them from Work Plan. Manual / playbook-created incidents skip the classifier — you set the type yourself.

Flow 1 · INC-4821 from mailbox to close
1 Fetch graph_phish_in 2 Classify type = Phishing 3 Map From / Subject / URL 4 Pre-process drop / link / keep 5 Incident INC-4821 · Phishing 6 Default playbook TC-Phish-Lab (Run automatically = on) parse → extract → !url / WildFire → condition on DBotScore → manual contain → close Each task: Context JSON + War Room entry (unless Quiet Mode hides I/O) Miss at 6: no branch on failed / empty enrichment → close task still runs. Fix the condition. Do not “reopen and hope.” War Room will show the error entry. Post-process script on the type runs after close (ticket close, reporter mail). It is not the playbook. Source: Cortex XSOAR Incident Lifecycle — xsoar.pan.dev/docs/incidents/incident-xsoar-incident-lifecycle

Read left → right, then the gold bar. Classifier picks the type; the type picks the playbook. Close is a playbook task plus optional post-process.

ObjectLab valueIf missing
Integration instancegraph_phish_in · Fetches incidents · mailbox phish@lab.techclick.inNothing in Incidents. Test with !graph_phish_in-fetch debug-mode=true.
ClassifierKey that maps this mailbox to type Phishing (or instance default type = Phishing)Wrong type → wrong default playbook. War Room playbook name will not be TC-Phish-Lab.
Incoming mapperEmail From, Email Subject, Email URL, occurred, severityData only in labels. Enrich task has empty input.
Incident typePhishing · default playbook TC-Phish-Lab · Run automaticallyIncident sits Unassigned / no Work Plan. You will run the playbook by hand forever.
Pre-processSame subject + same sender within 24h → Link and closeCampaign floods the queue; analysts investigate copies.
ProofWar Room: playbook tasks + !url result; Context: DBotScore.ScoreClosed with no score is a governance failure, not a FP.

Enrich, ask, or contain

Pick the automation level the type is allowed to run. Mixing them is the usual “the playbook isolated a VIP laptop” ticket.

Flow 2 · enrichment is not containment
Enrich standard tasks · !url !ip !file WildFire detonate · skip if unavailable writes DBotScore to Context Ask manual / data-collection Only assignee can complete condition: Score ≥ 3 or error Contain isolate / block / purge after the ask task, never before mark results as evidence Governance: duplicate OOTB (Phishing Investigation - Generic v2) → TC-Phish-Lab. Do not detach the pack playbook. Detached content stops receiving Marketplace updates. Attach after you finish, or keep the copy in your own pack. Empty DBotScore / task Error must take the ask branch, not the close branch. Skip-if-unavailable is for missing packs, not failed detonations. Source: Playbooks overview + Playbook Task Field Reference — xsoar.pan.dev/docs/playbooks

Three columns, three tickets. Do not toggle isolate to “make the playbook useful.”

NeedUseSkip
One mailbox, one typeInstance default incident type = Phishing. Classifier optional.A classifier key you cannot see in rawJSON.
One SIEM, many typesClassifier on event type / signature. Mapper per type.One default type for everything, then hoping the playbook branches.
Campaign noisePre-process: Link and close on same subject, oldest parent, 24h window.Drop until you have proven the parent exists.
Enrichment only (week 1)Standard tasks + skip-if-unavailable. No isolate commands on the graph.Quiet Mode on the whole playbook — you will lose the War Room you need to debug.
Containment (week 3+)Conditional on score + manual task, “Only the assignee can complete.”Auto-isolate from an OOTB sub-playbook you did not read.
Change OOTB logicDuplicate the playbook, point the type at the copy, version in a pack.Detach in place. Detach is drift.

Runbook Side A / B / C

Side A is ingest objects. Side B is the playbook graph. Side C is War Room proof. Do not start at C.

Side A — integration, classifier, type

  1. Install the pack, add the instance

    Marketplace → Microsoft Graph Mail (or EWS O365). Then Settings → Integrations → Servers & Services → Add instance. Name graph_phish_in. Fetches incidents = on. Mailbox phish@lab.techclick.in. Incident type fallback = Phishing. Click Test. Source: Cortex XSOAR Incident Lifecycle — Configure Integrations; integration instance Classifier / Mapper fields.

  2. Classifier then mapper

    Settings → Integrations → Classifications & Mapping (or Mapping next to the instance). Classifier: if this mailbox is phishing-only, instance default type is enough. Mixed SIEM: set a classification key in rawJSON, drag values to Phishing. Mapper: Edit Mapping on type Phishing — Email From, Email Subject, Email URL, occurred, severity. Unmapped stays in labels.

  3. Incident type + pre-process

    Incident Types (XSOAR 6: Settings → Advanced → Incident Types; XSOAR 8: Settings → Object Setup → Incidents → Types). Phishing: default playbook TC-Phish-Lab, Run playbook automatically = on, auto-extract = Out of band until you need inline scores. Pre-process: Settings → Integrations → Pre-Process Rules — first matching rule wins; Link and close campaign dupes to the oldest parent.

https://xsoar.lab.techclick.in/ · Settings → Integrations → Servers & Services → graph_phish_in
Training mock · not live

Settings › Integrations › Servers & Services › graph_phish_in

Microsoft Graph Mail · graph_phish_in

phish@lab.techclick.in
Enabled
Phishing mailbox classifier
Phishing incoming mapper
Phishing
Success — last fetch 2 incidents

Source: Classification and Mapping — Settings → Integrations → Classifications & Mapping; instance Classifier / Mapper / default incident type. Classifier overrides the fallback type. Test is not a fetch of production mail — use !graph_phish_in-fetch debug-mode=true when Test is green but Incidents is empty.

Side B — playbook then gates

https://xsoar.lab.techclick.in/ · Incident Types → Phishing
Training mock · not live

Incident Types › Phishing › Edit

Phishing

TC-Phish-Lab
On
Out of band
EmailAskUser (reporter close)

Source: Working with Incident Types — Default playbook, Run playbook automatically, Auto extract (None / Inline / Out of band), Post process using. Inline extract delays the playbook until enrichment finishes. Out of band does not put scores in Context in time for the next task — do not condition on DBotScore if extract is out of band and you did not run !url yourself.

  1. Duplicate OOTB, do not detach

    Playbooks → open Phishing Investigation - Generic v2 → Duplicate as TC-Phish-Lab. Point the Phishing type at the copy. Detaching the pack playbook freezes you on that version when Marketplace ships fixes.

  2. Graph: enrich → condition → ask → contain → close

    Section header “Enrich.” Standard tasks: parse email, extract indicators, !url / WildFire detonate with Skip this branch if this automation/playbook is unavailable and retries. Conditional: DBotScore.Score ≥ 3 or task error / empty output → “Ask analyst.” Manual task: Isolate endpoint? Only the assignee can complete. Containment commands only on the Yes edge. Close with reason + notes on both Yes (True Positive) and No (False Positive). Mark detonation output as evidence.

Playbook contract — TC-Phish-Lab (lab)
Inputs:  EmailURL  from incident field (mapper), fallback ${incident.labels}
Outputs: DBotScore, WildFire.Report, IsolateResult

Enrich (standard)
  !url url=${incident.emailurl}
  wildfire-upload / wildfire-report   # skip if unavailable
  Number of retries: 3 · Retry interval: 30s

Condition
  YES: DBotScore.Score >= 3
  ERR: task state = Error OR DBotScore is empty   → same YES (ask, do not close)
  NO:  Score 0–2 and task completed

Ask (manual)
  Name: Approve isolate / block?
  Only the assignee can complete the task: on
  SLA: 30m · reminder: 10m

Contain (standard, Yes edge only)
  isolate / block-url / mailbox-purge
  Mark results as evidence: on

Close
  !closeInvestigation closeReason="..." closeNotes="War Room entry IDs …"
Skip-if-unavailable ≠ ignore errors

Skip-if-unavailable is for a missing pack or disabled instance so the rest of the graph can run. A WildFire task that ran and failed is an Error entry. Route Error to Ask. Quiet Mode still records errors; it hides inputs/outputs you wanted for the RCA.

Side C — prove it in the War Room

  1. Trigger one mail, open the incident

    Send the lab URL https://203.0.113.80/owa-login to phish@lab.techclick.in. Incidents → INC-4821. Type must be Phishing. Work Plan must show TC-Phish-Lab, not an OOTB name you did not choose. Source: Incident Lifecycle — Running Playbooks.

  2. War Room filters

    War Room → filter Commands and playbook tasks, then Errors. You want the !url / WildFire human-readable result, not only a green Work Plan. Marked evidence should appear under Evidence. Notes are tagged entries — use them for the close narrative.

  3. Context, then close

    Context Data: DBotScore.Indicator, DBotScore.Score, URL.Data. Empty score + Closed = the bug in the ticket. Re-run the failed task from Work Plan, or from CLI with debug-mode=true. Then close with a reason that cites the War Room entry.

War Room CLI — proof (lab)
!graph_phish_in-test-module debug-mode=true
!graph_phish_in-fetch debug-mode=true
# log file attaches to the War Room when debug-mode=true

!url url="https://203.0.113.80/owa-login"
# expect DBotScore in Context; human-readable table in War Room

# Context Data tab → DBotScore.Score / URL.Data
# Score missing → do not close. Fix mapper input or the enrich instance.

# after analyst decision:
!closeInvestigation closeReason="False Positive" closeNotes="WildFire verdict benign; War Room entry attached"
Green proof

INC-4821 type Phishing, Work Plan = TC-Phish-Lab, War Room has the enrich command result, Context has DBotScore.Score, and if Score ≥ 3 the manual task is waiting — not already Closed. That is the close of the lab, not a green integration Test button.

One phish after go-live

Mail lands in phish@lab.techclick.in. Graph Mail fetch builds rawJSON. Classifier (or instance default) sets type Phishing. Mapper writes Email URL = https://203.0.113.80/owa-login. Pre-process does not match a parent. Incident INC-4821 is created. Type runs TC-Phish-Lab. Extract + !url write Context. Score 3 → Ask task blocks on the assignee. Analyst isolates from the Yes edge. Evidence tagged. !closeInvestigation True Positive. Post-process mails the reporter. War Room holds every command; Context holds the scores the report will quote.

Failure path: WildFire times out. Condition sees empty Score → Ask, not Close. If you never built that condition, the close task runs and the queue looks clean. That is INC-4821 as filed.

Proof · close is a War Room trail, not a dashboard tile
Analyst at a SOC desk reviewing a playbook completion checklist on a large monitor
Ops feel. The actual evidence is War Room command/task entries plus Context DBotScore. Artwork checkmarks are not XSOAR.
Where to look when Work Plan is green and the verdict is wrong
Incidents → INC-4821
  Info:     type, playbook name, close reason
  Work Plan: which task is completed / error / waiting
  War Room:  Commands and playbook tasks · Errors
  Context:   DBotScore.Score · URL.Data · incident.emailurl
  Evidence:  detonation report marked as evidence

If type ≠ Phishing: Classification & Mapping, not the playbook editor.
If emailurl empty: incoming mapper. Labels will still have the raw key.
If task Error and status Closed: missing condition — add Error → Ask.

Traps + proof

SymptomLikely causeProof
Playbook never startsRun playbook automatically off, or classifier sent a type with no default playbook.Incident type field vs Playbooks → that type’s Default playbook.
Wrong playbook name in Work PlanClassifier miss; instance fallback type won.Settings → Classifications & Mapping; unmapped values sit under the fallback.
Enrich task has no URLMapper did not map the attribute; it is only in labels.Context incident.labels vs incident.emailurl.
Closed while WildFire never returnedNo condition on Error / empty DBotScore. Close task is unconditional.War Room error entry + empty Context score + closeReason set.
VIP laptop isolatedContainment on the automatic edge; no manual task / no “Only assignee.”Work Plan: isolate task completed by Playbook, not a user.
OOTB playbook “won’t save my edit”Content is attached; or you detached and now pack updates skip you.Playbook menu: Detached vs Duplicate. Prefer the copy in your pack.
Test is green, no incidentsFetch not enabled, fetch window, or pre-process Drop.!instance-fetch debug-mode=true; Pre-Process Rules order (first match wins).
Quiet Mode “lost the output”Quiet Mode hides I/O and skips auto-extract; errors still log.Turn Quiet off on the enrich task for the pilot.
Do not detach Phishing Investigation - Generic v2 to “make it ours”

Duplicate, bind the type to TC-Phish-Lab, ship the copy in your content pack. Detach is how production drifts from Marketplace and how the next pack upgrade looks like a regression.

Pilot checklist

Knowledge check

Six judgment items. Submit once. Reasons point back at the section to re-read.

Q1

Graph Mail fetch is green. INC-4821 ran “Default” instead of TC-Phish-Lab. What actually selects the playbook that auto-runs?

Correct: b. Classifier/fallback → type → type’s default playbook. Re-read Why Closed is not a verdict and Flow 1.
Q2

The enrich task’s URL input is empty, but the raw event clearly has a link. First place to look?

Correct: a. Mapper fills indexed fields. Labels are the leftovers. Re-read Four objects and Side A.
Q3

Which pair is the right mental model for War Room vs Context?

Correct: c. Next-task inputs come from Context. RCA and audit come from War Room. Re-read Four objects and Side C.
Q4

Week-1 production rollout for a new phishing type. Safest graph?

Correct: b. Enrich first, contain later behind Ask. Re-read Enrich, ask, or contain and Side B.
Q5

You need to change an OOTB phishing playbook. What keeps Marketplace upgrades?

Correct: d. Duplicate, don’t detach. Re-read Flow 2 and the detach callout.
Q6

INC-4821 is Closed / False Positive. War Room shows the WildFire task in Error and Context has no DBotScore. Root cause?

Correct: a. Error / empty score must go to Ask, not Close. Re-read Flow 1, Side B, and Traps.

Sources

Related: Cortex XDR architecture · Xpanse attack surface · Palo Alto operator stack