Skip to content
incident-responseintermediate#sigma#detection-engineering#siem#blue-team#yara

Sigma Rules: Portable Detections for Any SIEM

How Sigma rules work: the YAML structure, log sources, the detection block and condition syntax, field modifiers, correlations, and converting one rule into Splunk, Sentinel or Elastic queries with sigma-cli.

A detection written in Splunk's search language runs in Splunk. Move to Sentinel and it is rewritten in KQL. Move to Elastic and it is rewritten again. Every migration throws away years of tuning, and every published detection in a blog post arrives in a query language that half the readers do not run.

Sigma is the answer to that. A rule is a YAML file describing what to look for in log events, with no product-specific syntax, and a converter turns it into the query language of whichever system you use. Write once, convert to Splunk, KQL, Elasticsearch, QRadar, Chronicle or a dozen others.

The project started in 2017 and the public repository at SigmaHQ now holds thousands of community rules mapped to ATT&CK techniques. This guide covers the format itself, the parts that go wrong, and the conversion workflow.

Scope: What Is a SIEM owns the pipeline these rules run inside, YARA Rules Explained owns the file and memory equivalent, and MITRE ATT&CK Framework Explained owns the technique taxonomy the tags reference.

The anatomy of a rule

A complete rule, then a walk through each part:

title: Encoded PowerShell Command Line
id: 6e2a5d4b-0f43-4c17-9a3d-2b0f7c8e91aa
status: experimental
description: >
  Detects powershell.exe launched with an encoded command argument, which is
  used to pass a base64 payload without it appearing in the command line.
references:
  - https://attack.mitre.org/techniques/T1059/001/
author: Detection Team
date: 2026-08-25
tags:
  - attack.execution
  - attack.t1059.001
logsource:
  category: process_creation
  product: windows
detection:
  selection_img:
    - Image|endswith: '\powershell.exe'
    - OriginalFileName: 'PowerShell.EXE'
  selection_flag:
    CommandLine|windash|contains:
      - ' -enc'
      - ' -ec '
      - ' -EncodedCommand'
  filter_management:
    ParentImage|endswith: '\ccmexec.exe'
  condition: selection_img and selection_flag and not filter_management
falsepositives:
  - Endpoint management platforms that pass encoded commands to agents
  - Some vendor installers
level: medium

Metadata. title is what appears in the alert, so it should say what happened rather than what technique it belongs to. id is a UUID and is how the rule is tracked across forks and versions; generate a fresh one for a new rule and keep it stable forever after. status runs experimental, test, stable, deprecated, unsupported, and it matters operationally: experimental means nobody has confirmed the false positive rate in a real estate.

Tags map to ATT&CK, which is what makes coverage measurable. attack.t1059.001 is the sub-technique, attack.execution the tactic.

Log source is the triple that decides what data the rule applies to and, crucially, which processing pipeline will be used at conversion time. category is a generic event type such as process_creation, network_connection, file_event or registry_set. product is the platform, such as windows, linux or aws. service names a specific log, such as security, sysmon or cloudtrail. A rule using category: process_creation with product: windows can be converted against Sysmon Event ID 1 or against Windows Event ID 4688 depending on the pipeline, which is exactly the portability the format exists for.

Detection is the substance, and it has one required key.

The detection block

Everything in detection except condition is a named search. The names are yours; the convention is selection* for things you want and filter* for things you want removed.

Inside a named search, a map of field to value means all of the pairs must match, so this requires both:

  selection:
    Image|endswith: '\powershell.exe'
    User: 'NT AUTHORITY\SYSTEM'

A list of values under one field means any of them, so this matches if the command line contains either string:

  selection:
    CommandLine|contains:
      - 'Invoke-Expression'
      - 'IEX ('

A list of maps means any of the maps, which is how you express alternatives across different fields. In the example rule, selection_img matches on either the image path or the original file name from the PE header, and the second exists because renaming powershell.exe to totallynotpowershell.exe defeats a path check while leaving OriginalFileName intact.

condition then combines the named searches with and, or, not and parentheses. It also supports quantifiers that keep long rules readable:

  condition: 1 of selection_* and not 1 of filter_*
  condition: all of selection_* and not filter_main

Keeping exclusions in their own named search and subtracting them in the condition is worth doing consistently. It makes the exception visible in code review, it lets you comment on why the exception exists, and it means removing an exception is a one-line change rather than surgery on a compound expression.

Modifiers do the real work

A bare Field: value is an exact match. Modifiers change that, and choosing the wrong one is the most common reason a rule matches nothing or matches everything.

ModifierBehavior
containsSubstring anywhere in the value
startswith / endswithAnchored at either end
reRegular expression, at the cost of performance and portability
cidrValue is an IP inside the given network range
base64 / base64offsetEncodes the search value so it matches encoded data
allWith a list, every listed value must match rather than any
windashExpands a leading dash to the variants Windows accepts
expandSubstitutes a placeholder resolved by the pipeline at conversion

Three of these deserve detail.

endswith on paths. Image|endswith: '\powershell.exe' is deliberate. Matching the full path breaks when the binary is in an unusual location, matching contains: 'powershell' also hits powershell_ise.exe and any file with the word in its name, and the leading backslash on endswith prevents matching a file called notpowershell.exe.

base64offset|contains. A base64 string embedded in a larger command line does not necessarily start on a 3-byte boundary, so the same plaintext produces three different encodings depending on its offset. base64offset generates all three, and chaining |contains searches for any of them inside the field. This is what makes a rule find an encoded payload without decoding anything.

windash. Windows command-line parsers accept several characters as the argument prefix, including the hyphen, the forward slash, and Unicode dash characters that look like a hyphen and are not. An attacker substituting one of those defeats a rule that searched for the ASCII hyphen. windash expands the search across the set.

The related trap is abbreviation. PowerShell accepts any unambiguous prefix of a parameter name, so -EncodedCommand also works as -encodedc, -enco, -enc and -ec. A rule searching only for the full parameter name catches the lazy and misses everyone else, which is why the example rule lists the short forms.

Correlations

A single-event rule cannot express "twenty of these in five minutes" or "this, then that". The Sigma correlation types cover those.

title: Multiple Failed Logons Followed by a Success
id: 8f1c2e77-a4d9-4f60-8f3c-5c7a1e0d92bb
correlation:
  type: event_count
  rules:
    - failed_logon_rule_id
  group-by:
    - TargetUserName
  timespan: 5m
  condition:
    gte: 20

The types are event_count for a number of matching events, value_count for a number of distinct values of a field (which is how you express "one source authenticating against 30 different accounts"), temporal for several different rules firing within a window in any order, and temporal_ordered for the same with the order enforced.

Backend support for correlations varies more than support for basic rules, so check what your target produces before designing a detection library around them.

Converting a rule

The current tooling is sigma-cli, built on the pySigma library. The older sigmac tool from the original repository is superseded.

pipx install sigma-cli
sigma plugin list
sigma plugin install splunk
 
# Convert one rule, using the Sysmon pipeline to map field names
sigma convert -t splunk -p sysmon rules/encoded_powershell.yml
 
# A whole directory, output as a Splunk savedsearches stanza
sigma convert -t splunk -p sysmon -f savedsearches rules/windows/

Three flags carry the weight. -t picks the backend, meaning the target query language. -p picks one or more processing pipelines. -f picks the output format, because most backends can emit a plain query, an alert definition, or a product-specific configuration file.

The pipeline is the part that gets forgotten. Sigma rules use generic field names. Your data does not. A pipeline maps Image to whatever your ingestion produced, which might be process.executable under the Elastic Common Schema, NewProcessName if you are reading Windows 4688 rather than Sysmon, or Process_Path if a parser named it that. Convert without the right pipeline and you get a syntactically perfect query referencing fields that do not exist in your index. It returns zero results and looks like a quiet environment, which is the same failure described in What Is a SIEM and just as invisible.

The check is mechanical and takes two minutes: generate the event the rule targets on a test host, find that event in your SIEM, and confirm the converted query returns it.

Running a rule library

A repository of thousands of community rules is a starting point rather than a detection strategy.

Filter by status and log source. Rules for a product you do not run, or against telemetry you do not collect, are noise in the repository. Start from the sources you actually ingest and the ATT&CK techniques you care about.

Never ship experimental rules straight to alerting. Run them in a monitoring-only mode, count how often they fire over a week, and promote the ones with a workable rate. A repository dumped into an alert queue produces thousands of events a day and trains analysts to close alerts unread.

Version control with tests. Each rule gets a pull request, a reviewer and, where practical, an Atomic Red Team test that generates the behavior so CI can confirm the rule fires. A detection nobody has ever seen fire is untested.

Track false positives in the rule. The falsepositives field exists for this. When you tune an exception in, write down why, so the next person does not remove it.

Re-convert on schema changes. When ingestion changes, field names change, and every converted query built on the old mapping silently stops matching. Conversion belongs in the pipeline that deploys detections rather than in someone's terminal history.

The verdict

Sigma solves a narrow problem well: describing a log-based detection in a form that survives a change of SIEM and can be reviewed as code. The format is small, the semantics of the detection block are learnable in an afternoon, and the modifiers cover the string handling that detections actually need.

Two things determine whether it works in practice. The pipeline has to map Sigma's field names onto your data, or every rule compiles cleanly and detects nothing. And the rules need the same lifecycle as any other code: review, tests, tuning and retirement. The format gives you portability, and the discipline around it gives you detection.

Sources & further reading