Sigma Rules Done Right: Best Practices That Survive Production

Tips for writing portable, effective detections with Sigma.

A laptop glowing with a large sigma symbol

Sigma promised write once, detect everywhere. In practice, most shared rules die on contact with a real environment: too broad, too brittle, or silently mistranslated. The difference between a Sigma rule that works and one that pages you at 3 a.m. is a handful of disciplines.

Sigma's value is real: a vendor-neutral way to describe log detections, a huge community corpus, and a compiler into most query languages. But portability cuts both ways. A rule written loosely enough to run anywhere is usually written loosely enough to fire everywhere. These are the practices that keep the portability without the pain.

One rule, one behavior

The most common failure in shared rules is scope creep: a single rule trying to catch every variant of a technique with a forest of OR branches. Broad rules are impossible to tune, because every exclusion you add for one branch weakens another. Write one rule per distinct behavior and let collections group them.

yamlsuspicious-certutil-download.yml
title: Certutil Remote Download
id: 8f2a...
status: production
description: certutil.exe fetching remote content, a common LOTL download primitive
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    Image|endswith: '\certutil.exe'
    CommandLine|contains:
      - 'urlcache'
      - 'verifyctl'
  filter_intune:
    ParentImage|endswith: '\IntuneManagementExtension.exe'
  condition: selection and not filter_intune
falsepositives:
  - Endpoint management tooling (filtered)
level: high
tags:
  - attack.command_and_control
  - attack.t1105

Everything that makes this rule maintainable is metadata discipline: a real description, an explicit false-positive register, a technique tag, and a named filter with a reason. Six months from now, someone who is not you will have to decide whether this rule still deserves to exist. Leave them the evidence.

Field mapping is where rules go to die

Sigma rules do not run; their translations run. The compiler maps Sigma's field names onto your SIEM's schema, and every unmapped field silently becomes a rule that matches nothing. The rule shows green in the console and catches zero events forever.

  • Keep a golden dataset of sample events per log source, and replay it after every schema or pipeline change.
  • Audit for rules with zero matches in 90 days: they are either miracles of prevention or broken mappings, and it is usually the mapping.
  • Pin your backend and mapping versions: a converter upgrade can change semantics under a rule without touching its YAML.

Tune with filters, not by lowering severity

When a rule is noisy, the tempting move is dropping it from high to low so it stops paging. This is how SOCs accumulate thousands of rules that fire into a void. Severity describes the behavior's impact; noise is a precision problem, and precision is fixed with named filters, each carrying a comment that says what it excludes and why.

A downgraded alert is not tuned. It is muted, and muted is where breaches hide.

Where Sigma ends and baselines begin

Sigma describes point-in-time patterns beautifully and describes normal terribly. "certutil downloading a file" fits in YAML. "This service account has never authenticated to that host before" does not, because normal is a property of your history, not of a pattern. The strongest programs use Sigma for the known and behavioral baselines for the unknown, and refuse to force either tool into the other's job.

See Port0 on your own data.

Bring your noisiest alert queue. Watch Soc0 investigate it live.

Book a Demo

Never Miss an Insight

Subscribe to get the latest posts delivered to your inbox.