Files
riposte-marketplace/integrations/cortex-xdr/manifest.yaml
T
f3nris e973ccb673 feat(cortex-xdr): endpoint_count counts agents below a target build (1.10.0)
agent_version_lt, compared number by number in the script, as the
endpoints API does not filter on the agent version either. Folded into
the unpushed 1.10.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LaiNEwG2W5Y9fMo4qXcesr
2026-10-13 08:49:29 +00:00

717 lines
47 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
id: cortex_xdr
name: Cortex XDR
version: 1.10.0
description: "Palo Alto Cortex XDR (public API v1) — incident and alert ingestion + write-back, endpoint isolation/scan/delete/tagging, XQL queries against the data lake, RTR scripts, hash block/allow lists, file quarantine/restore/retrieval, alert exclusions, external alert push (parsed/CEF), device-control violations, audits, distributions and RBAC/risk."
changelog: "1.10.0 — endpoint_count takes an operational_status filter (protected, partially_protected, unprotected), so an agent reporting playbook can count the agents in error the way SentinelOne's operationalStatesNin does, and an agent_version_lt filter to count the agents below a target build (8.5 reads as 8.5.0.0), as agentVersion__lt does. The endpoints API filters on neither field, so the endpoints the other filters match are read 100 at a time and counted by the script: one call per hundred endpoints, where the other filters cost one call. | 1.9.0 — The full-incident mapper gives an incident a title of its own. Title and description both read the incident's description, so every ticket showed the same sentence twice, and the title ran to the host and user it already named. The title is now the rule that fired (the first alert's name), with '(+N other alerts)' when several detections are folded into the incident, or the incident's name when someone renamed it in the console. The description keeps XDR's sentence and adds what each distinct rule means, from the alerts' own descriptions. The network destination no longer mixes two flows: network_artifacts[0] came last and overwrote the alert's connection piecemeal — one artifact's hostname and IP next to the alert's port, a destination the alert never reached. The artifacts are now only the fallback, and the destination country is read from the artifact XDR built for the alert's own remote IP, since action_country is UNKNOWN on most network alerts. Also mapped: the rule's description and id (finding_info.analytic.desc / uid), and the XDR assignee (assignee.name, assignee.email_addr). The bundled template is replaced on update; a mapper cloned from it keeps its own expressions and needs the same change by hand. | 1.8.0 — update_incident lists its status and manual_severity values as enums, so the playbook editor offers them in a drop-down and the command bar refuses a misspelt one. The status list is the API's: resolved_other joins it and resolved_auto leaves it, since that resolution is set by Cortex XDR itself. 1.7.0 — New endpoint_count command: counts endpoints matching filters without listing them. The endpoints grid already answers with reply.total_count — the number of matches, independent of the page asked for — so endpoint_count asks for a one-record page and reads it, where get-endpoints has to walk the estate 100 records at a time to reach the same figure, and only filters on four fields. Filters cover the twelve list fields the API accepts (hostname, alias, endpoint id, internal and public IP, group, platform, distribution, status, isolation, scan status, username), add first_seen/last_seen bounds taking ISO8601 or epoch ms, and leave a raw JSON `filters` escape hatch for the rest. The estate `total` comes back next to `count` so the figure reads as a proportion, and a filter too broad to mean anything shows as matching everything rather than passing for an answer. | 1.6.0 — Declare the risk tier on the 25 commands that carried none: 10 safe_write, 15 destructive. An unset risk is read as destructive by the agent approval gate, so the 10 that only annotate sat behind the same prompt as the ones that change the estate. | 1.5.0 — The full-incident mapper now carries the investigation. XDR names action_process_image_* the process an alert is actually about — the child a prevention module blocked — and it was mapped nowhere, so the single most investigable string in the payload, that process’s command line, existed only inside raw: on a Child Process Protection alert, a WScript.exe invocation on a .js file sitting in the user’s Downloads folder. It fills process.* now, the group the SentinelOne (targetProcessInfo) and Carbon Black (childproc_*) mappers already reserve for the process acted upon. The chain above it lands in process.lineage as OCSF Process objects, root-first and ancestry only, which is what lineage means in OCSF; a generation XDR leaves entirely null — os_actor on an agent-side prevention — drops out rather than showing as an empty level. Every alert’s chain also travels under a process_tree context key, deliberately not an OCSF field: process.lineage describes the ancestry of ONE process, and an XDR incident groups N alerts, each with its own chain and often a shared ancestor, which OCSF has no shape for. Nodes there carry their role because the chain is positional — nothing in the payload links a child to a parent, action_process_instance_id is null, and the *_causality_id fields name the causality GROUP rather than the node, so merging chains on a causality id fuses two distinct processes. Also mapped, all for the same reason: the actor’s pid and MD5, the causality actor’s command line (mapped in the alerts feed but not here), the endpoint’s FQDN, AD domain, MAC and OS build, the protection module that fired and the agent version, the firing alert’s id, the incident id as the correlation key both feeds join on, the activity kind, and the registry, DNS and user-agent fields the other alert kinds in this feed carry. action_country is dropped when it is the literal UNKNOWN, which XDR writes on alerts that have no network dimension at all: mapping it put a destination country on process-execution incidents that never had a destination. 1.4.0 — XQL. Four commands reach the data lake: cortex-xdr-xql-query runs a query and waits for its rows, cortex-xdr-xql-start-query and cortex-xdr-xql-get-query-results split that work in two when the query outlives a command, and cortex-xdr-xql-get-quota says what the day’s hunting has already cost — an XQL query is billed by the data it scans. Two things the API makes easy to get wrong are handled here. Past 1000 rows it stops answering with results and hands over a stream id instead: gzipped JSON lines, unpacked into rows rather than dropped on the playbook as an archive. And a query carrying no limit stage is served the tenant’s own default, so one is appended (100 rows, configurable) unless the query already has its own. Waiting is a budget, not a promise: a command is killed at 60 seconds, so a query still running comes back PENDING with its execution_id, which the results command collects afterwards — re-running the query would be charged against the quota a second time. 1.3.2 — The mappers fill the Actor group, as the HarfangLab and SentinelOne mappers already did. XDR names the process that acted actor_process_* and its account actor_effective_username, but both landed outside the actor: the process in process.*, the account in user.name — the OCSF slot for the user an event was done TO. So a Cortex tenant answered nothing to a correlation or pre-processing rule written on actor.user.name / actor.process.name, and any rule reading user.name as the victim read the attacker instead. actor_process_* now maps to actor.process.*, causality_actor_process_* to actor.process.parent_process.*, actor_effective_username to actor.user.name; process.* is left free for the process acted upon, which is what it holds in the SentinelOne (targetProcessInfo) and Carbon Black (childproc_*) mappers. On get_incidents_full the incident's impacted users[] and the first alert's user_name both wrote user.name, so the alert's actor overwrote the impacted user; they are now two fields. Rules and columns written against the old Cortex paths need repointing. 1.3.1 — get_incidents_full can watermark on modification_time (modified_after), which is what ingestion wants: an XDR incident keeps growing after creation, and a creation_time watermark fetches it once and never looks again, so every alert that joins it afterwards is lost. The full-incident fetch command is named cortex-xdr-get-incidents-full (id get_incidents_full), not cortex-xdr-fetch-incidents: sitting next to cortex-xdr-get-incidents in the command list, it now reads as what it is — the same call, everything included. A rule created against the old id must be pointed at the new one. 1.3.0 — Richer incident ingestion (get_incidents_full, on get_multiple_incidents_extra_data): incidents now arrive with their alerts in full and their file/network artifacts, where get_incidents only ever answered a 21-field summary carrying neither hosts, users, MITRE nor a single alert. Alert ingestion, and the alerts endpoint answers at last: get_alerts was sending the incidents dialect ({filters, search_from, search_to, sort}) to a grid endpoint that speaks request_data.filter_data (SEARCH_FIELD/SEARCH_TYPE/SEARCH_VALUE blocks, paging.from/to, sort as a list), and every call came back HTTP 500. Body rebuilt from the reference client, rows unwrapped out of their alert_fields envelope, severity code and the dotted status.progress key derived into readable fields. Alert ingestion: get_alerts is now a fetch command (results path reply.alerts, dedup on alert_id, incremental on source_insert_ts) with a bundled OCSF mapper and a Cortex XDR Alert incident type, so detections can be ingested alongside — or instead of — incidents. The incident mapper is fixed on the way past: its severity expression compared strings, which the mapping engine cannot do, so every ingested incident silently took the rule's default severity; it also now carries a detection anchor so MTTD is measurable. It pages past the API's 100-results-per-call ceiling, and sorts oldest-first on an incremental fetch so a truncated window drops the alerts the next poll can still see. 1.2.1 — Connection troubleshooting: the URL is normalised to the tenant host (a pasted /public_api/v1 or console path no longer breaks the call), a non-JSON reply reports the status, content type and body instead of a bare JSON parse error, missing key/key ID is caught up front, nonce and timestamp are sent in both auth modes as the reference client does, and test_connection now probes get_incidents. 1.2.0 — Incident write-back (update_incident: status/severity/assignment/resolve comment) and external alert push (insert_parsed_alerts, insert_cef_alerts). 1.1.0 — Full command coverage: added delete/alias/tag endpoints, abort scan, original alerts, script metadata/code/snippet/exec-status, file retrieval (+details), alert exclusions, device-control violations, audits, distribution url/status/create and RBAC (users, roles, groups, risk score, risky users/hosts). 1.0.0 — Initial release: incident ingestion (get_incidents) with OCSF mapper, endpoints, isolate/unisolate, scan, hash blocklist/allowlist, quarantine/restore, run script + results, alerts retrieval, distributions and action status. Standard or Advanced API authentication."
category: endpoint
# Per-instance configuration. The base URL is the tenant API root, e.g.
# https://api-yourtenant.xdr.eu.paloaltonetworks.com (scripts append /public_api/v1).
config_schema:
properties:
url:
type: string
description: "Tenant API host — Settings → Configurations → API Keys → Copy URL, e.g. https://api-<tenant>.xdr.<region>.paloaltonetworks.com. Not the console URL you log into (that one answers with HTML, not JSON)."
api_key_id:
type: string
description: "API Key ID (the integer ID shown next to the API key in Settings → API Keys)"
api_key:
type: string
description: "API Key secret"
x-soar-sensitive: true
auth_type:
type: string
description: "How the key was created in Cortex XDR: standard (key sent as-is) or advanced (nonce + timestamp SHA-256 hash). A mismatch here is rejected with 401."
default: standard
required:
- url
- api_key_id
- api_key
# Documented for reference; the bundled scripts build the headers themselves.
# Standard: x-xdr-auth-id: <id>, Authorization: <api_key>
# Advanced: x-xdr-auth-id: <id>, x-xdr-nonce, x-xdr-timestamp,
# Authorization: sha256(api_key + nonce + timestamp)
auth:
- id: apikey
type: api_key
in: header
name: Authorization
value_template: "{{secret}}"
secret_field: api_key
commands:
# ── Ingestion ─────────────────────────────────────────────────────────────
- id: get_incidents
name: cortex-xdr-get-incidents
description: "List Cortex XDR incidents as a 21-field summary (no hosts, no users, no MITRE, no alerts). Cheap to poll, but for ingestion prefer cortex-xdr-get-incidents-full, which returns the same incidents with their alerts and artifacts. Returns {reply:{incidents:[...]}}."
risk: read
inputs_schema:
properties:
status: { type: string, description: "Filter by status (e.g. new, under_investigation, resolved_threat_handled)" }
created_after: { type: string, description: "Lower bound on creation_time, ISO8601 or epoch ms (incremental fetch watermark)" }
limit: { type: number, description: "Maximum incidents to fetch (default 100)" }
required: []
outputs_schema: { properties: {} }
ingest:
results_path: reply.incidents
dedup_key: incident_id
incremental_field: created_after
- id: get_incidents_full
name: cortex-xdr-get-incidents-full
description: "Fetch incidents WITH their alerts and artifacts (get_multiple_incidents_extra_data) — the ingestion command to prefer. get_incidents answers with a 21-field summary carrying no hosts, no users, no MITRE and none of the alerts; this one returns 39 incident fields, every alert in full (156 fields each) and the file/network artifacts. Records are flattened, so mapping expressions written against get_incidents keep working and alerts[], file_artifacts[], network_artifacts[] sit beside them. Returns {reply:{incidents:[...]}}."
risk: read
inputs_schema:
properties:
status: { type: string, description: "Comma-separated statuses to keep (new, under_investigation, resolved_threat_handled…)" }
created_after: { type: string, description: "Lower bound on creation_time, ISO8601 or epoch ms. Watermarking on this fetches each incident once and never revisits it — alerts joining it later never arrive." }
modified_after: { type: string, description: "Lower bound on modification_time, ISO8601 or epoch ms. The watermark to prefer for ingestion: an incident comes back whenever it changes, and dedup on incident_id turns the second visit into an enrichment." }
limit: { type: number, description: "Maximum incidents to fetch (default 50, paged 50 at a time). A full incident weighs a few KB and up to a few hundred with its alerts, so raise this knowingly." }
exclude_artifacts: { type: boolean, description: "Drop the file and network artifact blocks, keeping the alerts (lighter payload)" }
required: []
outputs_schema: { properties: {} }
ingest:
results_path: reply.incidents
dedup_key: incident_id
incremental_field: modified_after
- id: get_incident_extra_data
name: cortex-xdr-get-incident-extra-data
description: "Get full incident data including its alerts and network artifacts by incident ID."
risk: read
inputs_schema:
properties:
incident_id: { type: string, description: "Incident ID" }
alerts_limit: { type: number, description: "Max alerts to return (default 1000)" }
required: [incident_id]
outputs_schema: { properties: {} }
- id: update_incident
name: cortex-xdr-update-incident
description: "Update an incident's status, severity, assignment and resolve comment (write-back / close the loop)."
risk: safe_write
inputs_schema:
properties:
incident_id: { type: string, description: "Incident ID to update" }
status:
type: string
description: "New status; a resolved_* value closes the incident with that resolution."
enum:
- new
- under_investigation
- resolved_threat_handled
- resolved_known_issue
- resolved_duplicate
- resolved_false_positive
- resolved_true_positive
- resolved_security_testing
- resolved_other
manual_severity:
type: string
description: "Override severity"
enum: [low, medium, high, critical]
assigned_user_mail: { type: string, description: "Assignee email" }
assigned_user_pretty_name: { type: string, description: "Assignee display name" }
unassign: { type: boolean, description: "Clear the assignment when true" }
resolve_comment: { type: string, description: "Resolution comment (shown when resolving)" }
required: [incident_id]
outputs_schema: { properties: {} }
- id: get_alerts
name: cortex-xdr-get-alerts
description: "Fetch Cortex XDR alerts for ingestion (get_alerts_by_filter_data). Returns {reply:{alerts:[...]}}; use reply.alerts as the alert rule results path. Each row is unwrapped out of the API's alert_fields envelope and carries a readable severity_name and status_progress, so alerts-grid field names (internal_id, alert_name, agent_hostname) are what mapping expressions see. Alerts are the detection layer under incidents: ingest them alongside get_incidents when the SOC works detections, not only aggregates."
risk: read
inputs_schema:
properties:
severity: { type: string, description: "Comma-separated severities (informational, low, medium, high, critical)" }
created_after: { type: string, description: "Lower bound on alert source_insert_ts, ISO8601 or epoch ms (incremental fetch watermark)" }
limit: { type: number, description: "Maximum alerts to fetch (default 100). The API serves 100 per call at most; above that the script pages until the limit is reached." }
# Left unfiltered, the call is bounded to the last 30 days: the alerts
# grid is not meant to be asked for a tenant's whole retention.
required: []
outputs_schema: { properties: {} }
ingest:
results_path: reply.alerts
dedup_key: internal_id
incremental_field: created_after
- id: insert_parsed_alerts
name: cortex-xdr-insert-parsed-alerts
description: "Push external alerts (parsed JSON objects) into Cortex XDR for correlation."
risk: safe_write
inputs_schema:
properties:
alerts: { type: string, description: "JSON array of parsed alert objects (each with product, vendor, severity, alert_name, etc.)" }
required: [alerts]
outputs_schema: { properties: {} }
- id: insert_cef_alerts
name: cortex-xdr-insert-cef-alerts
description: "Push external alerts in CEF format into Cortex XDR for correlation."
risk: safe_write
inputs_schema:
properties:
alerts: { type: string, description: "CEF alert lines: a JSON array of CEF strings, or newline-separated CEF lines" }
required: [alerts]
outputs_schema: { properties: {} }
# ── Endpoints ─────────────────────────────────────────────────────────────
- id: get_endpoints
name: cortex-xdr-get-endpoints
description: "List/search endpoints by hostname, IP, status, platform, group, etc."
risk: read
inputs_schema:
properties:
hostname: { type: string, description: "Hostname to filter by" }
ip_list: { type: string, description: "Comma-separated IPs" }
status: { type: string, description: "Endpoint status (connected, disconnected, ...)" }
platform: { type: string, description: "OS platform (windows, linux, macos, android)" }
limit: { type: number, description: "Max endpoints (default 30)" }
required: []
outputs_schema: { properties: {} }
- id: endpoint_count
name: cortex-xdr-endpoint-count
description: "Count endpoints matching filters, without listing them. The endpoints grid answers with reply.total_count — the number of matches, independent of the page asked for — so one call with a single-record page returns the figure, where cortex-xdr-get-endpoints would page 100 endpoint records at a time to arrive at it. Returns {count, total, filters}: count is the number of matching endpoints, total the whole estate, so the figure reads as a proportion and a filter that matched everything is visible rather than plausible."
risk: read
inputs_schema:
properties:
hostname: { type: string, description: "Comma-separated hostnames" }
alias: { type: string, description: "Comma-separated endpoint aliases" }
endpoint_id: { type: string, description: "Comma-separated endpoint (agent) IDs" }
ip_list: { type: string, description: "Comma-separated internal IPs" }
public_ip_list: { type: string, description: "Comma-separated public IPs" }
group_name: { type: string, description: "Comma-separated endpoint group names" }
platform: { type: string, description: "Comma-separated platforms (windows, linux, macos, android)" }
dist_name: { type: string, description: "Comma-separated distribution (installation package) names" }
status: { type: string, description: "Comma-separated endpoint statuses (connected, disconnected, lost, uninstalled)" }
isolate: { type: string, description: "Isolation state: isolated or unisolated" }
scan_status: { type: string, description: "Comma-separated scan statuses (none, pending, in_progress, canceled, aborted, pending_cancellation, success, error)" }
username: { type: string, description: "Comma-separated usernames logged on the endpoint" }
operational_status: { type: string, description: "Comma-separated operational statuses (protected, partially_protected, unprotected), e.g. partially_protected,unprotected for the agents in error. The API does not filter on it: the endpoints the other filters match are read 100 at a time and counted here" }
agent_version_lt: { type: string, description: "Only agents on a version strictly older than this one, e.g. 8.5 or 8.5.0.12345 — the fleet still to be upgraded to it. Compared number by number (8.5 reads as 8.5.0.0); an endpoint reporting no version is not counted. Like operational_status, counted by the script over the matching endpoints" }
first_seen_after: { type: string, description: "Lower bound on first_seen, ISO8601 or epoch ms — endpoints enrolled since that instant" }
first_seen_before: { type: string, description: "Upper bound on first_seen, ISO8601 or epoch ms" }
last_seen_after: { type: string, description: "Lower bound on last_seen, ISO8601 or epoch ms — endpoints seen since that instant" }
last_seen_before: { type: string, description: "Upper bound on last_seen, ISO8601 or epoch ms — endpoints silent since that instant" }
filters: { type: string, description: "Any other API filter, as a JSON array of {field, operator, value} objects, appended as-is. Filters are combined with AND; the API has no OR." }
required: []
outputs_schema: { properties: {} }
- id: isolate_endpoint
name: cortex-xdr-isolate-endpoint
description: "Network-isolate an endpoint by endpoint (agent) ID."
risk: destructive
inputs_schema:
properties:
endpoint_id: { type: string, description: "Endpoint (agent) ID to isolate" }
incident_id: { type: string, description: "Optional incident ID to associate the action with" }
required: [endpoint_id]
outputs_schema: { properties: {} }
- id: unisolate_endpoint
name: cortex-xdr-unisolate-endpoint
description: "Remove network isolation from an endpoint by endpoint (agent) ID."
risk: destructive
inputs_schema:
properties:
endpoint_id: { type: string, description: "Endpoint (agent) ID to unisolate" }
incident_id: { type: string, description: "Optional incident ID to associate the action with" }
required: [endpoint_id]
outputs_schema: { properties: {} }
- id: scan_endpoints
name: cortex-xdr-scan-endpoints
description: "Trigger a malware scan on endpoints matching the given filters (or all)."
risk: safe_write
inputs_schema:
properties:
endpoint_id_list: { type: string, description: "Comma-separated endpoint IDs (omit + use all=true to scan all)" }
hostname: { type: string, description: "Comma-separated hostnames" }
all: { type: boolean, description: "Scan all endpoints when true and no other filter is set" }
incident_id: { type: string, description: "Optional incident ID" }
required: []
outputs_schema: { properties: {} }
- id: get_policy
name: cortex-xdr-get-policy
description: "Get the policy name applied to an endpoint."
risk: read
inputs_schema:
properties:
endpoint_id: { type: string, description: "Endpoint (agent) ID" }
required: [endpoint_id]
outputs_schema: { properties: {} }
# ── Hash block / allow lists ──────────────────────────────────────────────
- id: blocklist_files
name: cortex-xdr-blocklist-files
description: "Add file hashes to the block list."
risk: destructive
inputs_schema:
properties:
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to block" }
comment: { type: string, description: "Optional comment" }
incident_id: { type: string, description: "Optional incident ID" }
required: [hash_list]
outputs_schema: { properties: {} }
- id: remove_blocklist_files
name: cortex-xdr-remove-blocklist-files
description: "Remove file hashes from the block list."
risk: destructive
inputs_schema:
properties:
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to remove" }
comment: { type: string, description: "Optional comment" }
incident_id: { type: string, description: "Optional incident ID" }
required: [hash_list]
outputs_schema: { properties: {} }
- id: allowlist_files
name: cortex-xdr-allowlist-files
description: "Add file hashes to the allow list."
risk: destructive
inputs_schema:
properties:
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to allow" }
comment: { type: string, description: "Optional comment" }
incident_id: { type: string, description: "Optional incident ID" }
required: [hash_list]
outputs_schema: { properties: {} }
- id: remove_allowlist_files
name: cortex-xdr-remove-allowlist-files
description: "Remove file hashes from the allow list."
risk: destructive
inputs_schema:
properties:
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to remove" }
comment: { type: string, description: "Optional comment" }
incident_id: { type: string, description: "Optional incident ID" }
required: [hash_list]
outputs_schema: { properties: {} }
# ── File quarantine / restore ─────────────────────────────────────────────
- id: quarantine_files
name: cortex-xdr-quarantine-files
description: "Quarantine a file by path + hash on the given endpoints."
risk: destructive
inputs_schema:
properties:
endpoint_id_list: { type: string, description: "Comma-separated endpoint IDs" }
file_path: { type: string, description: "Full path of the file to quarantine" }
file_hash: { type: string, description: "SHA-256 of the file" }
incident_id: { type: string, description: "Optional incident ID" }
required: [endpoint_id_list, file_path, file_hash]
outputs_schema: { properties: {} }
- id: restore_file
name: cortex-xdr-restore-file
description: "Restore a quarantined file by hash."
risk: destructive
inputs_schema:
properties:
file_hash: { type: string, description: "SHA-256 of the file to restore" }
endpoint_id: { type: string, description: "Optional endpoint ID" }
incident_id: { type: string, description: "Optional incident ID" }
required: [file_hash]
outputs_schema: { properties: {} }
- id: get_quarantine_status
name: cortex-xdr-get-quarantine-status
description: "Check whether a file is quarantined on an endpoint."
risk: read
inputs_schema:
properties:
endpoint_id: { type: string, description: "Endpoint ID" }
file_path: { type: string, description: "File path" }
file_hash: { type: string, description: "SHA-256 of the file" }
required: [endpoint_id, file_path, file_hash]
outputs_schema: { properties: {} }
# ── Real-time scripts ─────────────────────────────────────────────────────
- id: run_script
name: cortex-xdr-run-script
description: "Run a script (by UID) on endpoints with optional parameters."
risk: destructive
inputs_schema:
properties:
script_uid: { type: string, description: "Script UID" }
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
parameters: { type: string, description: "JSON object of parameter values" }
timeout: { type: number, description: "Timeout in seconds (default 600)" }
incident_id: { type: string, description: "Optional incident ID" }
required: [script_uid, endpoint_ids]
outputs_schema: { properties: {} }
- id: get_script_execution_results
name: cortex-xdr-get-script-execution-results
description: "Get the results of a script execution by action ID."
risk: read
inputs_schema:
properties:
action_id: { type: string, description: "Action ID returned by run_script" }
required: [action_id]
outputs_schema: { properties: {} }
- id: get_scripts
name: cortex-xdr-get-scripts
description: "List available scripts, optionally filtered by name/description/OS support."
risk: read
inputs_schema:
properties:
name: { type: string, description: "Comma-separated script names" }
windows_supported: { type: boolean, description: "Filter scripts supporting Windows" }
required: []
outputs_schema: { properties: {} }
# ── XQL search ────────────────────────────────────────────────────────────
- id: xql_query
name: cortex-xdr-xql-query
description: "Run an XQL query and wait for its rows: the query is started, polled until the tenant answers, and the rows returned — including past the API's 1000-row ceiling, where results arrive as a gzipped stream this command unpacks. A command is killed at 60 seconds, so a query still running when the wait budget expires comes back with status PENDING and its execution_id: hand that to cortex-xdr-xql-get-query-results instead of running the query again, which is charged against the XQL quota a second time. Returns {reply:{status, execution_id, result_count, results:[...], query_cost, remaining_quota}}."
risk: read
inputs_schema:
properties:
query: { type: string, description: "XQL query, e.g. dataset = xdr_data | filter event_type = ENUM.PROCESS | fields agent_hostname, action_process_image_name" }
time_frame: { type: string, description: "Relative window, written as <number> <unit>: 30 minutes, 24 hours, 7 days, 2 weeks, 3 months. Left empty, and with no from_time/to_time, the tenant applies its own default — the last 24 hours, not all of time." }
from_time: { type: string, description: "Absolute lower bound, ISO8601 or epoch ms. Wins over time_frame; on its own, the window runs up to now." }
to_time: { type: string, description: "Absolute upper bound, ISO8601 or epoch ms." }
limit: { type: number, description: "Row ceiling, appended to the query as a limit stage when it carries none of its own (default 100) — without one the tenant serves its own default. Past 1000 rows the results come back as a gzipped stream, unpacked here, so raise this knowingly: every row is held in memory." }
tenant_ids: { type: string, description: "Comma-separated tenant IDs to query, on a multi-tenant (MSSP) deployment. Empty queries the tenant the API key belongs to." }
wait: { type: number, description: "Seconds to wait for the rows before answering PENDING (default 45, capped at 55 — the command itself is killed at 60)." }
required: [query]
outputs_schema: { properties: {} }
- id: xql_start_query
name: cortex-xdr-xql-start-query
description: "Start an XQL query and return its execution_id without waiting for the rows — for a query too slow for the 60-second command ceiling, or a playbook with something else to do while the tenant works. The rows are collected afterwards with cortex-xdr-xql-get-query-results. Returns {reply:{execution_id, query, status}}."
risk: read
inputs_schema:
properties:
query: { type: string, description: "XQL query" }
time_frame: { type: string, description: "Relative window, written as <number> <unit>: 30 minutes, 24 hours, 7 days, 2 weeks, 3 months. Empty leaves the tenant's default (the last 24 hours)." }
from_time: { type: string, description: "Absolute lower bound, ISO8601 or epoch ms. Wins over time_frame." }
to_time: { type: string, description: "Absolute upper bound, ISO8601 or epoch ms." }
limit: { type: number, description: "Row ceiling, appended as a limit stage when the query carries none (default 100)." }
tenant_ids: { type: string, description: "Comma-separated tenant IDs (multi-tenant deployments)" }
required: [query]
outputs_schema: { properties: {} }
- id: xql_get_query_results
name: cortex-xdr-xql-get-query-results
description: "Collect the rows of an XQL query started earlier. A query still running answers status PENDING with no rows, which is not a failure — poll again. Past 1000 rows the API hands over a stream id rather than the rows; the gzipped JSON lines behind it are unpacked here. Returns {reply:{status, result_count, results:[...]}}."
risk: read
inputs_schema:
properties:
execution_id: { type: string, description: "Execution ID returned by cortex-xdr-xql-start-query (the API calls it query_id — either input name is accepted)" }
required: [execution_id]
outputs_schema: { properties: {} }
- id: xql_get_quota
name: cortex-xdr-xql-get-quota
description: "Read the XQL quota: what the licence allows, what was purchased on top of it, and what the last 24 hours have consumed. A query is billed by the data it scans, so this is what says whether a hunting playbook can still run today."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
# ── Actions / misc ────────────────────────────────────────────────────────
- id: action_status
name: cortex-xdr-action-status
description: "Get the status of a group action by action ID."
risk: read
inputs_schema:
properties:
action_id: { type: string, description: "Group action ID" }
required: [action_id]
outputs_schema: { properties: {} }
- id: get_distribution_versions
name: cortex-xdr-get-distribution-versions
description: "List available agent installer versions."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
- id: delete_endpoints
name: cortex-xdr-delete-endpoints
description: "Delete endpoints (agents) by ID."
risk: destructive
inputs_schema:
properties:
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs to delete" }
required: [endpoint_ids]
outputs_schema: { properties: {} }
- id: set_endpoint_alias
name: cortex-xdr-set-endpoint-alias
description: "Set the alias name on endpoints."
risk: safe_write
inputs_schema:
properties:
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
alias: { type: string, description: "New alias name (empty to clear)" }
required: [endpoint_ids]
outputs_schema: { properties: {} }
- id: abort_scan
name: cortex-xdr-abort-scan
description: "Abort a running malware scan on endpoints matching the filters (or all)."
risk: safe_write
inputs_schema:
properties:
endpoint_id_list: { type: string, description: "Comma-separated endpoint IDs (omit to abort all)" }
incident_id: { type: string, description: "Optional incident ID" }
required: []
outputs_schema: { properties: {} }
- id: get_original_alerts
name: cortex-xdr-get-original-alerts
description: "Get the original raw alert events by alert ID."
risk: read
inputs_schema:
properties:
alert_id_list: { type: string, description: "Comma-separated alert IDs" }
required: [alert_id_list]
outputs_schema: { properties: {} }
- id: get_script_metadata
name: cortex-xdr-get-script-metadata
description: "Get metadata for a script by UID."
risk: read
inputs_schema:
properties:
script_uid: { type: string, description: "Script UID" }
required: [script_uid]
outputs_schema: { properties: {} }
- id: get_script_code
name: cortex-xdr-get-script-code
description: "Get the source code of a script by UID."
risk: read
inputs_schema:
properties:
script_uid: { type: string, description: "Script UID" }
required: [script_uid]
outputs_schema: { properties: {} }
- id: run_snippet_code_script
name: cortex-xdr-run-snippet-code-script
description: "Run an arbitrary code snippet on endpoints."
risk: destructive
inputs_schema:
properties:
snippet_code: { type: string, description: "Code snippet to run" }
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
incident_id: { type: string, description: "Optional incident ID" }
required: [snippet_code, endpoint_ids]
outputs_schema: { properties: {} }
- id: get_script_execution_status
name: cortex-xdr-get-script-execution-status
description: "Get the status of a script execution by action ID."
risk: read
inputs_schema:
properties:
action_id: { type: string, description: "Action ID" }
required: [action_id]
outputs_schema: { properties: {} }
- id: retrieve_file
name: cortex-xdr-retrieve-file
description: "Retrieve files from endpoints by OS-specific path lists."
risk: safe_write
inputs_schema:
properties:
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
windows: { type: string, description: "Comma-separated Windows file paths" }
linux: { type: string, description: "Comma-separated Linux file paths" }
macos: { type: string, description: "Comma-separated macOS file paths" }
incident_id: { type: string, description: "Optional incident ID" }
required: [endpoint_ids]
outputs_schema: { properties: {} }
- id: retrieve_file_details
name: cortex-xdr-retrieve-file-details
description: "Get the download details of a file-retrieval action."
risk: read
inputs_schema:
properties:
action_id: { type: string, description: "Group action ID from retrieve_file" }
required: [action_id]
outputs_schema: { properties: {} }
- id: add_exclusion
name: cortex-xdr-add-exclusion
description: "Add an alert exclusion."
risk: destructive
inputs_schema:
properties:
name: { type: string, description: "Exclusion name" }
indicator: { type: string, description: "JSON indicator object for the exclusion filter" }
status: { type: string, description: "ENABLED or DISABLED (default ENABLED)" }
required: [name, indicator]
outputs_schema: { properties: {} }
- id: delete_exclusion
name: cortex-xdr-delete-exclusion
description: "Delete an alert exclusion by ID."
risk: destructive
inputs_schema:
properties:
alert_exclusion_id: { type: number, description: "Exclusion ID" }
required: [alert_exclusion_id]
outputs_schema: { properties: {} }
- id: get_exclusion
name: cortex-xdr-get-exclusion
description: "List alert exclusions."
risk: read
inputs_schema:
properties:
tenant_id: { type: string, description: "Optional tenant ID" }
required: []
outputs_schema: { properties: {} }
- id: add_tag_endpoint
name: cortex-xdr-add-tag-endpoint
description: "Add a tag to endpoints."
risk: safe_write
inputs_schema:
properties:
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
tag: { type: string, description: "Tag to add" }
required: [endpoint_ids, tag]
outputs_schema: { properties: {} }
- id: remove_tag_endpoint
name: cortex-xdr-remove-tag-endpoint
description: "Remove a tag from endpoints."
risk: safe_write
inputs_schema:
properties:
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
tag: { type: string, description: "Tag to remove" }
required: [endpoint_ids, tag]
outputs_schema: { properties: {} }
- id: get_device_control_violations
name: cortex-xdr-get-device-control-violations
description: "List device control (USB) violations."
risk: read
inputs_schema:
properties:
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
type: { type: string, description: "Comma-separated violation types" }
timestamp_gte: { type: string, description: "Lower bound timestamp (ISO8601 or epoch ms)" }
required: []
outputs_schema: { properties: {} }
- id: list_users
name: cortex-xdr-list-users
description: "List Cortex XDR users."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
- id: get_risk_score
name: cortex-xdr-get-risk-score
description: "Get the risk score of a user or host by ID."
risk: read
inputs_schema:
properties:
id: { type: string, description: "User or host identifier" }
required: [id]
outputs_schema: { properties: {} }
- id: list_risky_users
name: cortex-xdr-list-risky-users
description: "List risky users."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
- id: list_risky_hosts
name: cortex-xdr-list-risky-hosts
description: "List risky hosts."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
- id: list_user_groups
name: cortex-xdr-list-user-groups
description: "Get user groups by name."
risk: read
inputs_schema:
properties:
group_names: { type: string, description: "Comma-separated group names" }
required: []
outputs_schema: { properties: {} }
- id: list_roles
name: cortex-xdr-list-roles
description: "Get roles by name."
risk: read
inputs_schema:
properties:
role_names: { type: string, description: "Comma-separated role names" }
required: []
outputs_schema: { properties: {} }
- id: set_user_role
name: cortex-xdr-set-user-role
description: "Assign a role to users."
risk: destructive
inputs_schema:
properties:
user_emails: { type: string, description: "Comma-separated user emails" }
role_name: { type: string, description: "Role name to assign" }
required: [user_emails, role_name]
outputs_schema: { properties: {} }
- id: remove_user_role
name: cortex-xdr-remove-user-role
description: "Remove the role assignment from users."
risk: destructive
inputs_schema:
properties:
user_emails: { type: string, description: "Comma-separated user emails" }
required: [user_emails]
outputs_schema: { properties: {} }
- id: audit_management_logs
name: cortex-xdr-audit-management-logs
description: "Retrieve management audit logs."
risk: read
inputs_schema:
properties:
email: { type: string, description: "Comma-separated emails" }
type: { type: string, description: "Comma-separated log types" }
timestamp_gte: { type: string, description: "Lower bound timestamp (ISO8601 or epoch ms)" }
limit: { type: number, description: "Max records (default 100)" }
required: []
outputs_schema: { properties: {} }
- id: get_audit_agent_reports
name: cortex-xdr-get-audit-agent-reports
description: "Retrieve agent audit reports."
risk: read
inputs_schema:
properties:
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
type: { type: string, description: "Comma-separated report types" }
timestamp_gte: { type: string, description: "Lower bound timestamp (ISO8601 or epoch ms)" }
limit: { type: number, description: "Max records (default 100)" }
required: []
outputs_schema: { properties: {} }
- id: get_distribution_url
name: cortex-xdr-get-distribution-url
description: "Get the download URL of an agent installer distribution."
risk: read
inputs_schema:
properties:
distribution_id: { type: string, description: "Distribution ID" }
package_type: { type: string, description: "Package type (sh, rpm, deb, pkg, x86, x64, ...)" }
required: [distribution_id, package_type]
outputs_schema: { properties: {} }
- id: get_distribution_status
name: cortex-xdr-get-distribution-status
description: "Get the build status of an agent installer distribution."
risk: read
inputs_schema:
properties:
distribution_id: { type: string, description: "Distribution ID" }
required: [distribution_id]
outputs_schema: { properties: {} }
- id: create_distribution
name: cortex-xdr-create-distribution
description: "Create an agent installer distribution."
risk: safe_write
inputs_schema:
properties:
name: { type: string, description: "Distribution name" }
platform: { type: string, description: "Platform (windows, linux, macos, android)" }
package_type: { type: string, description: "standalone or upgrade (default standalone)" }
agent_version: { type: string, description: "Agent version" }
description: { type: string, description: "Optional description" }
required: [name, platform]
outputs_schema: { properties: {} }
- id: test_connection
name: cortex-xdr-test-connection
description: "Verify connectivity and credentials (used by the Test button)."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
ingestion:
command: get_incidents
mapper: get_incidents
default_incident_type: "Cortex XDR Incident"