| name | xsiam-correlations |
| description | This skill should be used when the user asks to "create a correlation rule", "build a detection rule", "write a detection", "XSIAM alert rule", "correlation JSON", "detection engineering", "build a detection for", or needs to generate correlation rule JSON files with embedded XQL detection logic.
|
Correlation Rule Generation
Scope
Generate correlation rule .json files for Cortex XSIAM. Each output file contains a
JSON array with a single rule object wrapping XQL detection logic, alert metadata,
severity, MITRE ATT&CK mapping, and suppression configuration.
This skill handles:
- Real-time single-event correlation rules
- Scheduled threshold / aggregation correlation rules
- Dynamic severity correlation rules (numeric score to severity mapping)
- MITRE ATT&CK mapping for detection rules
- Suppression configuration for alert deduplication
This skill does NOT handle:
- Standalone XQL queries without a JSON wrapper -- use
xsiam-xql
- SPL-to-XQL translation -- use
xsiam-splunk-to-xql
- Automation scripts triggered by alerts -- use
xsiam-scripts
- Playbook workflows for alert response -- use
xsiam-playbooks
Before Starting
Always Read
Load these reference files before generating any correlation rule:
../xsiam-shared/references/xql-core-reference.md -- XQL syntax, stage order, operators
../xsiam-shared/references/xql-datasets-core.md -- Dataset names and field schemas
references/correlation-rule-spec.md -- Correlation JSON field specification and templates
Read On-Demand (when the detection query needs these)
../xsiam-shared/references/xql-advanced-functions.md -- Complex functions (arraymap, arrayfilter, join); also date/time formatting or parsing, IP-address tests/conversions, and math beyond add/subtract
../xsiam-shared/references/xql-datasets-extended.md -- Vendor-specific raw datasets
../xsiam-shared/references/xql-federated-search.md -- Cross-tenant federated queries
references/correlation-examples.md -- Complete worked examples for each execution mode
Workflow
Step 1: Understand the Detection Goal
Gather from the user:
- Behavior to detect -- What malicious or suspicious activity triggers the alert?
- Data source -- Which dataset(s) contain the relevant events?
- Severity -- How critical is this detection? Is severity static or dynamic?
- Context -- Any suppression requirements, MITRE mappings, or specific thresholds?
If the user provides only a high-level description (e.g., "detect brute force attacks"),
ask clarifying questions before proceeding.
Step 2: Select Execution Mode
Choose between:
| Mode | When to Use | Schedule Fields |
|---|
REAL_TIME | Single-event detections -- each matching event triggers an alert | search_window: null, simple_schedule: null, timezone: null, crontab: null |
SCHEDULED | Aggregation / threshold detections -- runs on a schedule | All four required: search_window (lookback), simple_schedule (human-readable), timezone, crontab (cron expression) |
Guidelines:
- Use
REAL_TIME when every matching event is independently alertable
- Use
SCHEDULED when the detection requires counting, grouping, or comparing across events
search_window for SCHEDULED should cover at least 2x the cron interval to avoid gaps
- REAL_TIME XQL is limited to a small stage set — see Step 3 and the Quality Checklist for the authoritative list
Step 3: Write the XQL Detection Query
Build the XQL query following the standard stage order from xql-core-reference.md:
config (if needed for extended timeframe)
dataset / datamodel dataset / preset
filter -- narrow to relevant events
alter -- extract, transform, compute fields
comp -- aggregate (for threshold detections)
filter -- post-aggregation threshold
fields -- select output columns
REAL_TIME restriction: REAL_TIME rules support only a limited stage set and forbid
certain functions. See references/correlation-rule-spec.md § REAL_TIME and the REAL_TIME
item in the Quality Checklist below for the authoritative list.
All correlation rules: the call, top, and tag stages and dataset wildcards
(dataset in (<prefix>_*)) are not supported. Prefer time_frame_end() over
current_time() for relative-time comparisons — it stays correct across ingestion lag and
recovery re-runs. search_window is at most 7 days. See correlation-rule-spec.md
§ XQL Constraints (All Correlation Rules).
Critical rule: The XQL query contains detection logic ONLY. Do not set alert metadata
(name, severity, MITRE, suppression) inside the query. Those belong in the JSON fields.
Exception: Dynamic severity via if() is allowed in XQL when the source data has a
numeric score but no discrete severity field. In that case, compute xdm.alert.severity
in the query and set a static fallback severity in JSON.
JSON navigation in detection XQL: Follow the arrow-notation grammar in
../xsiam-shared/references/xql-core-reference.md § Arrow Notation (JSON Navigation) —
dot-path reads, bracketed reserved keys, and to_json_string(...) wrapping of
array-function results before reading leaves.
Step 4: Build the JSON Object
Populate all correlation rule fields following the canonical field order from
correlation-rule-spec.md. Key instructions:
- Prompt the user for
rule_id (integer) if not provided
- Set
is_enabled: true by default
- Include ALL fields in canonical order, including null fields for full export fidelity
- Two severity patterns:
- Static:
"severity": "SEV_030_MEDIUM", "user_defined_severity": null
- User Defined:
"severity": "User Defined", "user_defined_severity": "field.reference"
alert_fields is an object mapping display names to XDM paths: {"email": "xdm.source.user.upn"}
alert_name and alert_description can use $field variable references
- When
suppression_enabled is false, set suppression_duration and suppression_fields to null
Step 5: Map MITRE ATT&CK
Assign relevant MITRE ATT&CK technique(s) and tactic(s) using labeled format:
"mitre_defs": {
"TA0006 - Credential Access": [
"T1110 - Brute Force"
]
}
- Tactic keys:
"TA#### - Tactic Name"
- Technique values:
"T#### - Technique Name" or "T####.### - Sub-technique Name"
- Empty object
{} when no MITRE mapping applies
- Map to the most specific technique available; prefer sub-techniques when applicable
Step 6: Configure Suppression
Set suppression to prevent alert fatigue:
suppression_enabled -- true for most detections
suppression_duration -- Human-readable format: "1 hours", "30 minutes", "15 minutes"
suppression_fields -- Which fields define a "duplicate" (e.g., ["source_ip"], ["user_name"])
- When suppression is disabled, set
suppression_duration and suppression_fields to null
Refer to the suppression patterns table in correlation-rule-spec.md for recommended
values by detection type.
Step 7: Deliver Output
Deliver:
- A
.json file containing a JSON array with one rule object: [{...}]
- All fields in canonical order from
correlation-rule-spec.md, including null fields
- XQL query serialized as a JSON string with
\n for newlines
- A companion markdown summary block explaining key design decisions (execution mode
choice, severity pattern, suppression rationale, MITRE mapping rationale)
Output Format
The final output is a .json file containing a single-element JSON array:
[
{
"rule_id": 100,
"name": "Rule Name",
"severity": "SEV_030_MEDIUM",
"xql_query": "dataset = xdr_data\n| filter event_type = ENUM.EVENT_LOG\n| filter action_evtlog_event_id = 4625\n| fields agent_hostname, action_evtlog_event_id",
"is_enabled": true,
"description": "Detects ...",
"alert_name": "Rule Name",
...
}
]
After the JSON file, include a companion markdown summary:
### Design Decisions
- **Execution mode:** [rationale]
- **Severity:** [rationale]
- **Suppression:** [rationale]
- **MITRE mapping:** [rationale]
Quality Checklist
Before delivering the correlation rule, verify ALL of the following:
- Output is valid JSON -- no trailing commas, proper quoting, correct nesting
- Output wrapped in array --
[{...}] even for single rules
- All fields present -- all 29 fields in canonical order, including null fields
rule_id is an integer -- prompted from user if not provided
- Severity enum valid -- one of:
SEV_010_INFO, SEV_020_LOW,
SEV_030_MEDIUM, SEV_040_HIGH, SEV_050_CRITICAL,
or "User Defined"
dataset always "alerts"
action always "ALERTS" (Save-to-Dataset / Add-to-Lookup / Remove-from-Lookup
actions exist but are out of scope for this skill)
mitre_defs uses labeled format -- tactic-to-technique with
"TA#### - Name": ["T#### - Name"], at most 3 tactics and 3 techniques
alert_category valid -- one of the 16 enum values (e.g., OTHER,
CREDENTIAL_ACCESS, LATERAL_MOVEMENT) or "User Defined"; see spec
drilldown_query_timeframe -- "ALERT" or "QUERY"
- Duration strings use human-readable format --
"1 hours", "15 minutes",
"30 minutes" (not shorthand)
- REAL_TIME schedule fields are null --
search_window, simple_schedule,
timezone, crontab all null
- REAL_TIME XQL uses only supported stages --
dataset/datamodel, filter,
alter, fields, config case_sensitive (no comp, sort, dedup, join);
a filter stage is present; no json_extract_scalar_array/parse_epoch/time_frame_end
- No unsupported stages in any rule -- no
call, top, tag, or dataset wildcards
- Relative time uses
time_frame_end() not current_time(); search_window <= 7 days
- XQL contains detection logic only -- alert metadata in JSON fields
(exception: dynamic severity via
alter/if())
- Suppression fields match detection type -- fields that define "duplicate"
for this specific detection
- Companion markdown summary included -- explains execution mode, severity,
suppression, and MITRE choices