A Sigma rule is only useful if it runs in your SIEM. Conversion from Sigma YAML to SIEM-native queries is the step where subtle errors introduce silent failures. This lesson covers the conversion workflow and the pitfalls to watch for.
The Conversion Workflow
Sigma Rule (.yml)
│
▼
sigma-cli / Uncoder
│ field mapping pipeline
▼
Field names translated to SIEM-specific names
│
│ syntax generation
▼
SIEM-native query (SPL / KQL / EQL / etc.)
│
▼
Deploy to SIEM → Test → Ship
sigma-cli: Command-Line Conversion
Installation
pip install sigma-cli
# Install backend plugins
pip install pySigma-backend-splunk
pip install pySigma-backend-microsoft365defender
pip install pySigma-backend-elasticsearch
# List available backends and pipelines
sigma list backends
sigma list pipelines
Basic conversion
# Convert to Splunk SPL using Sysmon field mappings
sigma convert \
-t splunk \
-p sysmon \
rules/proc_creation_win_powershell_download_cradle.yml
# Convert to KQL (Microsoft Sentinel) using Windows Security Events pipeline
sigma convert \
-t microsoft365defender \
-p windows_audit \
rules/proc_creation_win_powershell_download_cradle.yml
# Convert entire directory
sigma convert \
-t elasticsearch \
-p ecs-windows \
rules/windows/process_creation/
Converting our PowerShell Download Cradle rule
sigma convert -t splunk -p sysmon rules/powershell-download-cradle.yml
Output (SPL):
(Image="*\\powershell.exe" (CommandLine="*New-Object*" CommandLine="*Net.WebClient*")
OR (Image="*\\powershell.exe" (CommandLine="*Invoke-WebRequest*" OR CommandLine="*wget*"
OR CommandLine="*curl*")) OR (Image="*\\powershell.exe" CommandLine="*Start-BitsTransfer*"))
NOT CommandLine IN ("*WindowsUpdate*","*MicrosoftUpdate*","*download.windowsupdate.com*")
And for Microsoft 365 Defender KQL:
DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where (ProcessCommandLine contains "New-Object" and ProcessCommandLine contains "Net.WebClient")
or ProcessCommandLine has_any ("Invoke-WebRequest", "wget", "curl")
or ProcessCommandLine contains "Start-BitsTransfer"
| where not (ProcessCommandLine has_any ("WindowsUpdate", "MicrosoftUpdate", "download.windowsupdate.com"))
What Gets Lost in Translation
Problem 1: Missing field mappings
If your Sigma rule uses a field that isn’t in the pipeline’s mapping, the converted query drops that condition:
# Sigma rule
detection:
selection:
Image|endswith: '\powershell.exe'
OriginalFileName: 'PowerShell.EXE' ← This field
If OriginalFileName isn’t in your Splunk pipeline mapping, sigma-cli silently drops it:
# Converted output (missing OriginalFileName):
Image="*\\powershell.exe"
The converted rule now only checks Image, not OriginalFileName — which means a renamed PowerShell binary would NOT be detected. The silent omission is dangerous: your rule appears to work but provides weaker coverage than intended.
Fix: Always review converted output. Look for missing conditions. Add custom field mappings to your pipeline for fields your environment uses.
Problem 2: Regex dialect differences
Sigma’s re: modifier converts to regex syntax, but regex dialects differ across systems:
detection:
selection:
TargetFilename|re: '.*\\AppData\\Local\\Temp\\[a-z]{8}\.exe'
In Elasticsearch Lucene: TargetFilename:/.*\\AppData\\Local\\Temp\\[a-z]{8}\.exe/
In Splunk: TargetFilename=/(.*\\AppData\\Local\\Temp\\[a-z]{8}\.exe)/
In KQL: TargetFilename matches regex @".*\\AppData\\Local\\Temp\\[a-z]{8}\.exe"
Backslash escaping differs. Test every regex-based rule after conversion.
Problem 3: Aggregation conditions
# Sigma aggregation
condition: selection | count() by ComputerName > 10
This converts differently:
SPL:
... | stats count by ComputerName | where count > 10
KQL:
... | summarize count_ = count() by ComputerName | where count_ > 10
EQL: EQL doesn’t support this directly — must be rewritten as ES|QL or a time-series query.
Uncoder.io: Web-Based Conversion
Navigate to uncoder.io, paste a Sigma rule, select the target platform, and copy the output. Uncoder supports 20+ SIEM platforms.
sigma-cli— SigmaHQ GitHub Uncoder.io— Uncoder pySigma backends— GitHub