Sigma Rules for Linux Threat Detection in 2026: Detection-as-Code with pySigma, Zircolite, and SIEM Backends
Sigma turns Linux auditd, journald, sshd, and sudo events into portable YAML detections that compile to any SIEM. Learn pySigma, sigma-cli, Zircolite, and CI patterns for detection-as-code in 2026.
Sigma is an open, vendor-neutral YAML format for describing log-based detections once and compiling them to any SIEM's query language (Splunk SPL, Elastic ES|QL, Loki LogQL, OpenSearch DSL, Sentinel KQL, and more). On Linux, Sigma rules turn auditd, journald, sshd, and sudo events into portable detection-as-code you can version, unit-test in CI, and ship to any backend without rewriting the logic. I run Sigma across a fleet of roughly 40k Linux hosts, and honestly, it's the only reason our detection library survived three SIEM migrations without a full rewrite.
Sigma rules are YAML files with a logsource, a detection block, and a boolean condition. The format is stable, and the SigmaHQ community ships around 3,000 curated rules under the DRL 1.1 license.
The classic sigmac Python 2 tool is deprecated. pySigma plus sigma-cli is the maintained path as of 2026, with first-class backends for Splunk, Elastic, Loki, OpenSearch, Sentinel, and Chronicle.
Zircolite runs Sigma rules offline against JSON, EVTX, auditd, and journald exports on a laptop. No SIEM required, ideal for IR triage.
Wazuh 4.9+ can consume Sigma rules through its integrator; Elastic Security ingests them via the Detection Engine; Grafana Loki uses the sigma-cli Loki backend.
Treat detections like code: pre-commit lint with sigma-cli check, unit-test with pytest against event fixtures, and gate merges on ATT&CK tag coverage.
The biggest footguns are field-name drift between ingest pipelines and untested rules that silently match zero events after a schema change.
What are Sigma rules and why do they matter on Linux?
Sigma is to SIEM detections what YARA is to file signatures: a portable, human-readable description of a bad thing, decoupled from any particular scanner. Florian Roth and Thomas Patzke published the first spec in 2016, and by 2026 it's the de facto interchange format between detection engineers, SOC analysts, and threat intel vendors. Instead of maintaining one index=linux sourcetype=auditd query in Splunk and a completely different event.category:file AND process.name:"chmod" query in Elastic, you write one Sigma YAML and let pySigma compile it to both.
My threat model for Sigma-on-Linux looks like this. What breaks first when a Linux estate has no shared detection format? Two things. The SOC re-implements the same detection three times (once per SIEM), and detection quality diverges. The Splunk version catches a technique the Loki version silently misses because someone forgot to backport it. Sigma collapses that N×M explosion into an N+M pipeline: N rules, M backends, one source of truth. It also gives you a shared vocabulary with the wider community. SigmaHQ ships thousands of vetted Linux rules covering initial access, privilege escalation, credential access, and lateral movement, all tagged to MITRE ATT&CK. If you're already investing in Linux auditd rules and SIEM integration, Sigma is the layer that makes that investment portable.
Every Sigma rule is a YAML document with a small, stable schema. The three load-bearing sections are logsource (what stream this rule reads), detection (named selection and filter blocks), and condition (a boolean expression combining those blocks). Everything else, title, id, status, author, tags, level, falsepositives, is metadata that the backend uses for triage and rule management. A minimal rule looks like this:
title: Suspicious Curl Piped to Shell
id: 3f6c2b8a-1e5d-4c31-9b45-8e2a1f9d7c40
status: experimental
description: Detects the classic "curl | sh" pattern often used by droppers and installer scripts.
author: Aisha Okonkwo
date: 2026/08/23
references:
- https://attack.mitre.org/techniques/T1105/
tags:
- attack.command_and_control
- attack.t1105
logsource:
product: linux
service: auditd
category: process_creation
detection:
selection_curl:
Image|endswith: '/curl'
CommandLine|contains:
- ' | sh'
- ' | bash'
- ' |sh'
- ' |bash'
filter_apt_mirrors:
CommandLine|contains: 'apt.example.internal'
condition: selection_curl and not filter_apt_mirrors
falsepositives:
- Internal package mirrors that legitimately pipe install scripts
level: high
Field modifiers like |contains, |endswith, |startswith, |re, |base64offset|contains, and |cidr are what make Sigma expressive without becoming regex soup. A list under a modifier is an implicit OR; a map with multiple keys is an implicit AND. Combine selections in condition with and, or, not, and aggregate helpers like count() by user > 5. The full grammar is documented in the SigmaHQ specification, and the schema is versioned. Sigma 2 (finalized 2024) added correlation rules that span multiple events, which is what you want for brute-force and low-and-slow detections.
Installing pySigma and sigma-cli on Linux
The legacy sigmac tool that shipped in the original repo was Python 2 and is officially deprecated. As of 2026 the maintained toolchain is pySigma (the library) and sigma-cli (the CLI wrapper), both from SigmaHQ. Install into a virtualenv so backend plugins don't pollute your system Python. I've seen more than one host break its distro python3 because someone pip install'd as root, and rebuilding that box was not a fun afternoon.
# Ubuntu 24.04 / Debian 13 / Rocky 10
sudo apt install -y python3-venv git
python3 -m venv ~/.venvs/sigma
source ~/.venvs/sigma/bin/activate
pip install --upgrade pip
pip install sigma-cli
# Add backends you actually need; each is a separate package
sigma plugin install splunk
sigma plugin install elasticsearch
sigma plugin install loki
sigma plugin install opensearch
# Verify
sigma list backends
sigma version
The sigma plugin command talks to the pySigma plugin directory and installs both the backend (which renders queries) and any pipelines it needs (which map generic Sigma field names to backend-specific field names). Pipelines are the piece nobody explains clearly. Sigma rules use logical field names like Image and CommandLine, but your ingest pipeline probably stores them as process.executable and process.command_line (ECS), or proc.name and proc.cmdline (Falco). The pipeline is the translation layer, and getting it wrong is the number-one reason a "working" rule returns zero hits in production.
Writing your first Linux Sigma rule against auditd
Let's write a rule that catches the pwnkit-shaped pattern: a non-root user executing a SUID binary with a suspiciously short argv. On Linux, the canonical event source is auditd with an execve rule armed. Assuming your auditd rules and SIEM integration already forward SYSCALL+EXECVE records as JSON, the Sigma looks like this:
title: Non-Root SUID Execve With Empty argv[1]
id: 8c4b7f1e-2a19-4b5f-9d84-6ef3a8b91d24
status: experimental
description: |
Detects a non-root user calling execve on a SUID-root binary with argc <= 1.
This shape appeared in CVE-2021-4034 (pwnkit) and several follow-on LPEs.
author: Aisha Okonkwo
date: 2026/08/23
tags:
- attack.privilege_escalation
- attack.t1548.001
logsource:
product: linux
service: auditd
detection:
selection:
type: 'SYSCALL'
syscall: 'execve'
uid|gt: 0
euid: 0
filter_argc:
argc|gte: 2
condition: selection and not filter_argc
fields:
- exe
- uid
- auid
- comm
- argc
falsepositives:
- Legitimate SUID helpers invoked with no arguments (rare, investigate each)
level: high
A few things worth calling out here. uid|gt: 0 uses the greater-than modifier introduced in pySigma 0.10, and older tooling would reject it, which is why version pinning matters. The filter_argc block is inverted in the condition with not, giving you the classic "selection minus known-good" pattern. And the fields list tells the backend which event fields to surface in the alert, so your on-call analyst doesn't have to pivot into raw logs just to see who ran what.
Convert it and dry-run against a fixture before shipping:
# Lint first; catches YAML errors and unknown fields
sigma check rules/linux/lpe_suid_short_argv.yml
# Convert to Splunk SPL
sigma convert -t splunk -p sysmon rules/linux/lpe_suid_short_argv.yml
# Convert to Elastic ES|QL with the ECS pipeline
sigma convert -t elasticsearch -p ecs_zeek_beats rules/linux/lpe_suid_short_argv.yml
Converting Sigma to Splunk, Elastic, Loki, and OpenSearch
The conversion command follows the same shape for every backend: sigma convert -t <backend> -p <pipeline> <rule-or-directory>. What differs is the emitted query language and the pipeline you pair with it. Here's the cheat sheet I keep pinned above my desk:
Backend
Package
Emits
Typical pipeline
Notes
Splunk
pysigma-backend-splunk
SPL, savedsearches.conf, ES notable
splunk_windows, splunk_linux_index
Ships correlation-rule support since 0.11
Elastic Security
pysigma-backend-elasticsearch
Lucene, EQL, ES|QL, KQL, NDJSON
ecs_zeek_beats, ecs_windows
Emit NDJSON to import as Detection Engine rules
Grafana Loki
pysigma-backend-loki
LogQL
loki_okta, loki_promtail_sysmon
Falls back to |~ regex for unsupported ops
OpenSearch
pysigma-backend-opensearch
Query DSL, monitor JSON
ecs_* from Elastic backend
Reuses most Elastic pipelines
Microsoft Sentinel
pysigma-backend-microsoft365defender
KQL
microsoft_365_defender
ATT&CK tags flow through to Sentinel's UI
For a directory of rules, point sigma convert at the folder and use -f to pick a file format. For example, -f savedsearches produces a Splunk savedsearches.conf you can drop into a TA, and -f siem_rule_ndjson produces an Elastic NDJSON bundle you can import via the Detection Engine API. The generated queries are deterministic given the same rule + pipeline + backend version, which is what makes CI diffs actually meaningful.
Running Sigma offline with Zircolite for IR triage
Not every situation gives you a SIEM. When I get paged for a suspected compromise on an isolated host, I want to run a few hundred Sigma rules against the local auditd and journald logs on the host itself, with no ingest pipeline and no ES cluster in the loop. Zircolite is a small Python tool that does exactly that. It loads Sigma rules, materializes each event stream into an ephemeral SQLite database, and runs the compiled SQL queries locally. It's my default first move on any Linux incident response engagement.
# Grab the logs from the suspect host (do this from your triage kit)
sudo ausearch --start today --raw > auditd.log
sudo journalctl -o json --since '7 days ago' > journal.json
# Run Zircolite against the auditd log with the Linux ruleset
python3 zircolite.py \
--evtx auditd.log \
--ruleset rules/rules_linux_sysmon.json \
--outfile detections.json \
--template templates/general_html_report.tmpl \
--templateOutput report.html
# Same idea against journald
python3 zircolite.py \
--evtx journal.json \
--ruleset rules/rules_linux.json \
--outfile journal-detections.json
Zircolite ships pre-compiled rulesets (Sigma converted with its own SQLite backend), so you don't need sigma-cli on the responder host. It runs on a plain Python 3.10+ interpreter with no external services, which matters when you're working on an air-gapped or half-firewalled machine. Pair it with YARA-X for on-disk malware hunting and Volatility 3 for memory forensics and you have a portable triage stack that fits on a USB stick.
Wiring Sigma into Wazuh, Elastic, and OpenSearch
For production monitoring you want Sigma running continuously against a live event stream, not offline in a Jupyter notebook. Three integrations cover most of the Linux world.
Elastic Security Detection Engine
Convert your ruleset to NDJSON and import via the Detection Engine API. Each Sigma rule becomes an Elastic detection rule with the ATT&CK tags mapped to Elastic's threat framework field. The Elastic Security team even publishes a mapping table showing which Sigma modifiers translate cleanly and which fall back to query_string.
Wazuh doesn't natively parse Sigma YAML, but the community sigma2wazuh converter emits Wazuh XML rulesets from Sigma sources. Point it at your Sigma repo, generate local_rules.xml, and let the Wazuh manager reload. This complements the setup covered in the existing multi-layer Linux IDS with AIDE, auditd, Wazuh, and Suricata walkthrough. Instead of hand-writing Wazuh XML, you author in Sigma and let CI regenerate the XML.
Grafana Loki
The Loki backend emits LogQL that runs inside Grafana Alloy or the Loki ruler. This works surprisingly well for shops that already ship journald to Loki via promtail and don't want a second SIEM standing up alongside it. The catch is that LogQL is line-oriented, so anything requiring cross-event correlation drops back to Loki's metric queries, which are less flexible than Elastic's EQL.
Detection-as-code: CI/CD, testing, and ATT&CK mapping
Detection engineering breaks when rules ship straight from someone's laptop into production. I hit this exact failure mode two jobs ago, and it cost us three weeks of alert fatigue before we cleaned up. The fix is the same pattern application code has used for a decade: version control, PR review, automated tests, and gated deploys. My blast-radius framing here is that a bad detection rule can either miss a real intrusion (silent failure) or generate so many false positives that the SOC starts ignoring the alert channel. Both are catastrophic in different ways, and testing is what keeps you honest.
The unit tests use pySigma's Python API to compile each rule into a callable predicate, then assert that a "true positive" fixture event matches and a "known good" fixture does not. This is where you catch schema drift: when the ingest pipeline renames process.name to process.executable.name, the test fails in CI, not silently in production three weeks later. For the ATT&CK check, walk the rules and assert every one has at least one attack.* tag. That's how you get coverage heatmaps that your CISO can actually read.
Pair Sigma with your existing telemetry from osquery fleet monitoring and Zeek network security monitoring. Zeek gives you network events, osquery gives you host state snapshots, and Sigma is the language you use to write detections across all three feeds without picking a favorite backend.
Common Sigma rule pitfalls and how to avoid them
After a few years of running this at scale, the failure modes are boringly consistent. Watch for these:
Field-name drift. The Sigma rule says CommandLine, the ingest pipeline stores process.command_line, and nobody wrote a pipeline mapping. Symptom: rule returns zero hits forever. Fix: mandatory unit tests with realistic fixture events.
Over-broad selections.CommandLine|contains: 'chmod' matches every configuration-management run in the fleet. Symptom: 5,000 alerts per day. Fix: pair every keyword selection with a specificity constraint (parent process, user context, path prefix).
Untested regex. A single |re modifier with a catastrophic backtracking pattern can DoS the Splunk search head. Fix: run rxxr2 or a similar ReDoS linter in CI.
Missing filter for internal tooling. The rule catches the attacker and your own SOAR playbook. Fix: keep an "allowlist" filter block per rule and document its assumptions.
ATT&CK tag rot. Sub-technique IDs change; MITRE renumbered several in the 2024 update. Fix: pin an ATT&CK version and run the SigmaHQ attack-taxonomy validator in CI.
Ignoring correlation rules. Single-event rules can't express "5 failed sudo attempts followed by a success within 60 seconds." Fix: use Sigma 2 correlation rules where the backend supports them (Splunk, Elastic, Sentinel all do as of 2026).
Frequently Asked Questions
What are Sigma rules used for?
Sigma rules describe log-based detections in a vendor-neutral YAML format. You write the detection once and compile it to any SIEM's query language (Splunk SPL, Elastic ES|QL, Loki LogQL, OpenSearch DSL, Sentinel KQL), so the same logic runs everywhere. On Linux, they cover process execution, authentication, file integrity, and network telemetry.
Is Sigma still maintained in 2026?
Yes. SigmaHQ is actively maintained, and the Sigma 2 specification (finalized 2024) added correlation rules and stronger typing. The legacy Python 2 sigmac tool is deprecated in favor of pySigma and sigma-cli, both under active development with regular backend releases.
Can Sigma rules run on Linux logs like auditd and journald?
Yes. Set logsource: {product: linux, service: auditd} (or journald, sshd, sudo, cron) in the rule header, and use the matching backend pipeline. SigmaHQ ships hundreds of Linux-specific rules under rules/linux/, and Zircolite can run them offline against exported log files.
What is the difference between Sigma and YARA?
YARA describes patterns in files or process memory (byte strings, imports, entropy). Sigma describes patterns in log events (process execution, authentication, network flows). They complement each other: YARA is your on-disk and in-memory scanner, Sigma is your log-based detection language, and both should live in the same detection-as-code repository.
How do you convert a Sigma rule to Splunk SPL?
Install the Splunk backend with sigma plugin install splunk, then run sigma convert -t splunk -p splunk_linux_index rule.yml. The -p flag selects the pipeline that maps Sigma's generic field names to your Splunk sourcetype fields. Using the wrong pipeline is the most common source of empty search results.
Does Wazuh support Sigma rules natively?
Not directly. Wazuh consumes its own XML rule format. Use the community sigma2wazuh converter to generate Wazuh XML from Sigma sources, run that conversion in CI, and deploy the resulting local_rules.xml to the Wazuh manager. This lets you keep a single Sigma source of truth even in a Wazuh-heavy environment.
Install Zeek 7.x on Linux, tune AF_PACKET for line-rate capture, write your first detection script, use JA4 TLS fingerprints, and stitch Zeek into a SIEM for real threat hunting.
A practical 2026 guide to fapolicyd on RHEL and Fedora: how it uses fanotify to gate execve, how to write rules that don't lock you out, the safe permissive-to-enforce rollout, and how it maps to CIS, STIG, and PCI DSS compliance.
A pipeline-first guide to Cilium 1.17 on Linux: writing CiliumNetworkPolicy resources with L7 HTTP/DNS/Kafka rules, wiring Hubble for flow observability, and validating every policy in CI before it reaches production.