Core architecture
what the platform is made ofThe platformorigin
Cortex XSOAR is Palo Alto Networks' Security Orchestration, Automation, and Response (SOAR) platform. It began as Demisto, acquired in 2019. The product name expands to eXtended Security Orchestration, Automation, and Response (XSOAR). It combines orchestration, automation, case management, and Threat Intelligence Management (TIM) in one platform.
Say the long form once in an interview and you sound like someone who knows what the letters mean, not someone repeating a product name.
XSOAR 6.x on-prem
Self-hosted on Linux. Single server, or distributed as an application server plus a database (DB). Uses Elasticsearch or the built-in BoltDB. You manage the container images and server configuration yourself.
XSOAR 8.x cloud
Software as a Service (SaaS), re-platformed onto the Cortex infrastructure that also runs Extended Security Intelligence and Automation Management (XSIAM). Multi-tenant for Managed Security Service Providers (MSSPs). Server configuration and container management move to Palo Alto's side.
Engines remote
Lightweight execution proxies installed in segmented networks or a demilitarized zone (DMZ) — integrations run locally there, so the main server never needs direct access to that segment. Load-balancing groups are supported.
Building blocks — know every one of these by name
!vt-comment-get.Playbooks
the job description's first lineTask types
- Standard — runs an automation or an integration command.
- Conditional — branches on context values, or runs a script returning a
yesornopath. - Manual — an analyst action; can block the playbook until completed.
- Data collection — sends a survey or form by email or Slack and waits for the response; answers land in context. This is how you gate containment on human approval.
- Sub-playbook — a nested playbook with its own isolated context unless inputs and outputs are passed explicitly.
- Section header — organization only, no execution.
Inputs, outputs, and loops
Playbooks declare inputs and outputs. Sub-playbooks receive inputs through filters and transformers from the parent context, and return declared outputs. Sub-playbooks can loop — "for each" over a context array, or loop until an exit condition. This is the standard pattern for iterating over multiple indicators or endpoints.
Filters and transformers
Inline data manipulation on any task input — filter on IP.Score >= 2, or transform with toLowerCase, Cut, Join, RegexExtract. Using these instead of a script avoids a container startup, which answers both a design question and a performance question.
Timers and service levels
Tasks can start, pause, and stop timer fields. This is how Mean Time To Respond (MTTR) and time-to-containment get measured per incident. SLA fields support breach actions.
Error handling
Tasks can be set to continue on error, and error paths can branch to retry or notification logic. Best practice is a dedicated error-handling sub-playbook rather than per-task patches.
Quiet mode
Suppresses War Room output per task or per playbook. On high-volume playbooks this is the single biggest control on database growth.
Execution model
Tasks run on the server, and each script executes inside its own Docker container tied to the integration or script image. Parallel branches execute concurrently.
Debugger
The built-in playbook debugger runs a playbook against a test incident with breakpoints, skipped tasks, and mocked inputs — validate before promoting to production.
Automations in XSOAR
where interviewers probe hardestScript anatomy
- Every script imports
demistomock as demistoandfrom CommonServerPython import *. demisto.args()— a dictionary of the task's arguments.demisto.context()anddemisto.incident()— read context and incident fields.demisto.executeCommand("cmd", args)— call another command from inside a script.return_results(CommandResults(...))— the modern return path.return_error("msg")— fail the task with an error.
# CommandResults — the four arguments that matter return_results(CommandResults( outputs_prefix='VirusTotal.IP', # where it lands in context outputs_key_field='id', # dedup key on repeat runs outputs=data, # the structured dictionary readable_output=tableToMarkdown('Result', data), # War Room view raw_response=raw # untouched API response ))
DBotScore — short for Demisto Bot Score — is the standard context object for reputation: Indicator, Type, Vendor, Score (0 to 3). Writing DBotScore is how an integration feeds platform-wide indicator scoring, and it is what makes verdicts vendor-agnostic.
Integration anatomy — the BaseClient pattern
class Client(BaseClient): # BaseClient from CommonServerPython def get_alert(self, alert_id): return self._http_request('GET', f'/alerts/{alert_id}') def main(): command = demisto.command() # dispatch on the command name if command == 'test-module': # the "Test" button return_results('ok') elif command == 'fetch-incidents': last = demisto.getLastRun() # dedup + pagination state ... demisto.setLastRun({'time': newest})
BaseClienthandles the base Uniform Resource Locator (URL), certificate verification and proxy flags, retries, and authentication headers.test-modulebacks the Test button — return'ok'on success.fetch-incidentspulls new alerts on a schedule, roughly every minute by default, and must manage last-run state withgetLastRunandsetLastRunfor deduplication and pagination.
Mirroring
Two-way synchronization of incident fields and comments with an external system such as ServiceNow or Cortex XDR, using get-remote-data and update-remote-data, with the mapper direction set to incoming or outgoing.
Docker images
Each script declares an image, for example demisto/python3:3.11.x. Custom dependencies mean a custom image (demisto/py3-tools or your own). In 6.x you manage images on the server; in 8.x Palo Alto hosts them.
Development workflow — the job description's "automation best practices"
- demisto-sdk — the official software development kit (SDK) command line tool:
init,validate,lint,format,upload,download,run. It lints with flake8, mypy, and bandit, and runs unit tests inside Docker. - Content as code: custom content lives in Git as packs in the standard directory structure. Continuous Integration and Continuous Delivery (CI/CD) — GitHub Actions or Jenkins — runs validate, lint, and pytest, then uploads to a development instance and promotes to production. This is SOAR as code, the same discipline as detection as code.
- Remote repositories — XSOAR can synchronize content directly from a Git repository for development-to-production promotion.
- Unit testing: pytest with
demistomock, mockingclient._http_request, with fixtures stored as JSON files intest_data/. - Packs are semantically versioned in
pack_metadata.json.
REST API & JSON
job description line twoWhat the letters mean
Representational State Transfer (REST) is an architectural style for web services: resources addressed by URL, acted on with HyperText Transfer Protocol (HTTP) verbs — GET to read, POST to create, PUT or PATCH to update, DELETE to remove — and stateless requests, meaning each call carries everything the server needs. JavaScript Object Notation (JSON) is the text format those calls carry: nested objects in braces, arrays in brackets, key and value pairs.
XSOAR's own REST API
- Authentication uses an API key header in 6.x; 8.x uses a key plus a key identifier, with standard and advanced key types.
POST /incident— create an incident.POST /incidents/search— query incidents.POST /entry— add a War Room entry.POST /entry/execute/sync— run a command and get results back.- The Generic Webhook integration receives inbound pushes from tools that cannot be polled, and creates incidents from the JSON body.
Third-party API patterns
- Authentication: an API key header; Open Authorization 2.0 (OAuth2) client credentials, where you fetch, refresh, and cache the token in integration context; or Hash-based Message Authentication Code (HMAC) request signing on some endpoint products.
- Pagination: offset and limit, cursor, or
Linkheaders — handled inside the fetch loop. - Rate limits: honor HTTP
429and theRetry-Afterheader;_http_requestsupports retry and backoff parameters. - Everything crossing the boundary is JSON — and XSOAR context is literally a JSON document, queried with dot notation and
[]filters.
Integration targets
one-liners that prove fluencySecurity Information and Event Management (SIEM)
SplunkPy integration fetches notable events from Enterprise Security (ES) using the notable macro. !splunk-search runs Search Processing Language (SPL) from inside a playbook, and mirroring pushes status and owner back to the notable. Splunk-side adaptive response actions can also trigger XSOAR.azure-log-analytics-execute-query.Endpoint Detection and Response (EDR)
xdr-get-incident-extra-data, xdr-isolate-endpoint, xdr-blocklist-files, xdr-run-script for Live Terminal, plus two-way incident mirroring.cs-falcon-contain-host, upload indicators, and execute commands through Real Time Response (RTR).Identity and Access Management (IAM)
ad-disable-account, ad-set-new-password, ad-expire-password, and group removal — the standard compromised-account containment set.Information Technology Service Management (ITSM)
ServiceNow: servicenow-create-ticket, query and update, plus mirroring — two-way synchronization of state, work notes, comments, and attachments between the ServiceNow ticket and the XSOAR incident. Jira follows the same pattern.
Enrichment and communications
VirusTotal version 3, AbuseIPDB, urlscan.io, Whois, and IPinfo, plus Recorded Future, Anomali, and the Malware Information Sharing Platform (MISP) through TIM. Slack and Microsoft Teams integrations send messages, ask questions through data-collection tasks, and mirror the War Room into a channel.
Standard response flow
the "walk me through a playbook" answerCanonical phishing and alert playbook — matches out-of-the-box content
- Ingest —
fetch-incidentsfrom the SIEM, EDR, or a mail listener. The classifier sets the type, the mapper fills the fields. - Deduplicate —
FindSimilarIncidentsand deduplication playbooks link or close duplicates. - Extract and enrich — auto-extraction pulls indicators, then
entityEnrichmentsub-playbooks for Internet Protocol (IP) address, URL, file, and domain produce DBotScore verdicts. - Triage and verdict — conditional tasks on scores and severity, using calculate-severity sub-playbooks.
- Contain — usually gated by a manual approval or data-collection task: isolate the endpoint through Cortex XDR or CrowdStrike, disable the account through Active Directory or Okta, and block the indicator at the firewall or proxy.
- Ticket and notify — create the ServiceNow ticket with mirroring enabled, and notify by Slack or email.
- Close — close notes, root-cause field, timers stopped, post-incident report generated. Service-level metrics feed the dashboards.
Threat Intelligence Management (TIM)
Feed integrations ingest indicators on a schedule. Indicators carry expiration, verdicts, and relationships. An External Dynamic List (EDL) publishes block lists over HTTP for Palo Alto Networks firewalls and proxies to consume directly — that is the loop from intelligence to enforcement without a human in the middle.
Troubleshoot & optimize
the volume tellTroubleshooting toolbox
/debug-modeon an integration instance gives full request and response logging.- The playbook debugger, with mocked context and breakpoints.
- Server logs at
/var/log/demistoin 6.x, plus!GetServerInfoand the system diagnostics page. - Classic failed-fetch causes: expired credentials or token, certificate verification failure, proxy blocking, a mapper or classifier mismatch, or corrupted last-run state — which is fixed by resetting last run.
- Container issues: a missing dependency means the wrong image; in hardened environments, check the container's outbound network rules.
Optimization levers — concrete, in order of impact
- Quiet mode and limiting War Room writes — the biggest database win on high-volume playbooks.
- Pre-processing rules — server-side rules at ingest that link, drop, or run a script before a playbook ever starts. The cheapest place to kill noise.
- Prefer filters and transformers over spawning scripts for trivial logic; every script means a container startup.
- Batch API calls inside integrations — one call for many indicators, not one call each.
- Context hygiene: use
outputs_key_fieldto deduplicate,DeleteContextto drop bulky raw responses after use, and never park full email bodies or packet captures in context. - Sizing reality: incident volume multiplied by playbook complexity drives database growth, so archive and purge policies on old incidents are part of the job.
Platform: Linux & Git
how the server and the content are managedLinux
XSOAR 6.x runs on Red Hat Enterprise Linux (RHEL), CentOS, Ubuntu, or Oracle Linux. It is installed by a shell installer and runs as the demisto systemd service. Engines follow the same pattern.
Git
Content packs live in GitHub. demisto-sdk validate and lint run in GitHub Actions, then a pull request (PR) review, upload to a development instance, and promotion to production. Branch per change, semantic version per pack.
Linux commands
the basics, and the ones that matter on a security boxMoving around and looking at files
cd .. goes up one, cd ~ goes home, cd - returns to the previous directory.tail -n 20 gives the last 20.Creating, copying, moving, deleting
Permissions and ownership
sudo -l lists what you are allowed to run.Searching and text processing — the analyst's toolkit
$1 is the first whitespace-separated column. Use -F, to split on commas instead.Pipes and redirection — how commands chain
>> appends instead.2>&1 merges errors into normal output.|| runs it only if the first failed.Processes, services, and resources
start, stop, restart, and enable for boot persistence.Networking and transfer
ifconfig.netstat.nslookup is the older equivalent.scp file user@host:/path copies files over the same channel.Packages, archives, and containers
apt install pkg on Debian and Ubuntu.docker logs <id> shows their output — how you debug a failing automation image.Python language
the fundamentals every automation usesData types — what you will be asked to name
"hello". Immutable — you cannot change it in place, only build a new one.True or False, capitalized.[1, 2, 3]. Indexed from zero.(1, 2).{"ip": "1.2.3.4"}. This is what JSON becomes when parsed — the single most important type in this job.{1, 2}. Useful for deduplicating indicators.if x is None, not == None.Control flow and functions
# Indentation defines blocks — Python has no braces if score >= 3: verdict = 'malicious' elif score == 2: verdict = 'suspicious' else: verdict = 'benign' # Loop over a list; enumerate() gives you the index too for i, ip in enumerate(ip_list): print(f'{i}: {ip}') # f-string: inline variables # while loops until the condition is false while has_more_pages: page += 1 # A function: def, name, parameters, optional default, return def score_indicator(value, threshold=2): """Docstring — what this does.""" return value >= threshold
breakexits a loop early;continueskips to the next iteration.- Comparison:
==equal,!=not equal,and,or,not, andinfor membership. - Indentation is syntax, not style. Four spaces is the standard.
Working with dictionaries and lists — the daily work
alert = {'id': 101, 'src': '10.0.0.5', 'tags': ['c2', 'beacon']}
alert['src'] # direct access — errors if the key is missing
alert.get('user', 'unknown') # safe access with a default — use this
alert.keys() alert.values() alert.items() # iterate over parts
for key, value in alert.items():
print(key, value)
# List comprehension — build a new list in one line
bad = [i for i in indicators if i['score'] >= 2]
# Common list operations
items.append(x) # add one to the end
items.extend(other) # add all of another list
len(items) # how many
items[0] items[-1] items[1:3] # first, last, slice
sorted(items, key=lambda x: x['score'], reverse=True)
The interview trap: alert['user'] raises a KeyError if the key does not exist. alert.get('user') returns None instead. In an integration parsing an unpredictable API response, always use .get().
JSON and API calls — the two libraries you will name
import json, requests # JSON: loads = text into Python, dumps = Python into text data = json.loads(response_text) # string -> dict text = json.dumps(data, indent=2) # dict -> string # A basic REST call with requests resp = requests.get( 'https://api.example.com/alerts', headers={'Authorization': f'Bearer {token}'}, params={'limit': 50}, timeout=30, # always set a timeout verify=True # certificate validation on ) resp.raise_for_status() # raise an error on 4xx / 5xx alerts = resp.json() # parse the body into a dict
Inside XSOAR you normally use BaseClient._http_request instead of calling requests directly, because it already handles proxy settings, certificate verification, retries, and error formatting. Knowing both, and saying why you prefer the platform one, is the strong answer.
Errors, files, and classes
# Exception handling — never let an integration die silently try: result = risky_call() except requests.Timeout: result = None # handle a specific error first except Exception as e: return_error(f'Call failed: {e}') # broad catch last finally: cleanup() # runs either way # Files — "with" closes the handle automatically with open('/tmp/out.json', 'w') as f: f.write(json.dumps(data)) # A class: blueprint, constructor, method class Client: def __init__(self, base_url, token): # runs on creation self.base_url = base_url self.token = token def get(self, path): # self = this instance return requests.get(self.base_url + path)
Idioms worth having ready
.lower(), .upper(), .replace().re module. The r prefix means a raw string, so backslashes stay literal.pip freeze > requirements.txt records exact versions for reproducible builds.Your defensible numbers
say these; back them up- 15+ years in security. Top Secret / Sensitive Compartmented Information (TS/SCI) clearance. Department of Defense, Federal, Enterprise, Health, and Finance.
- XSOAR playbook engineering at RedMatter and Palo Alto Networks — Federal Housing Finance Agency Splunk Enterprise Security notables feeding XSOAR response pipelines — and at Xbitium across XSIAM and XDR.
- 12 terabytes per day at 150,000+ events per second (EPS); 40% reduction in Mean Time To Respond; 25 to 50% false-positive reduction.
- Python microservices built with FastAPI and Flask, REST APIs, and webhooks; detection as code through GitHub Actions — the same continuous-integration discipline that SOAR content needs.
- Preferred-skill coverage: Splunk Enterprise Security (deep), Cortex XSIAM and XDR, ServiceNow ticketing flows, and Amazon Web Services and Microsoft Azure integrations.
Rapid-fire drill
30-second answersClick a card to reveal the answer. These are the classic screening questions.
get-remote-data and update-remote-data with a directional mapper.demisto.getLastRun() and demisto.setLastRun() every cycle, with pre-processing rules or deduplication playbooks as a second layer..get() returns None or a default you supply — essential when parsing an API response you do not fully control.systemctl status <service> for state, journalctl -u <service> -f to follow its logs live, df -h for a full disk, and ss -tulpn to confirm it is actually listening.