Checking SigmaHQ rules against real field lists

2026-07-08. Commands to reproduce at the end.

I ran detsema check over the Sysmon-backed part of SigmaHQ/sigma (fe2a6e8: 20 rule categories, 2,054 rules) using two field lists as ground truth:

  1. What Sysmon emits per event type, from the OSSEM-DD data dictionaries.
  2. The process_creation field table in the Sigma taxonomy appendix (v2.1.0), which defines the field names rules on the official repo may use.

Against Sysmon’s fields: 19 findings, one root cause

19 findings across 13 rules, under 0.7% of the corpus. Every one is the same problem: the rule filters on process context that its event type doesn’t carry. Sysmon network, image-load and file events have no CommandLine or ParentImage; remote-thread events have no SourceCommandLine or TargetParentProcessId. These rules depend on an enrichment step, usually an EDR, joining process information onto the event.

Where the missing field sits in the rule decides the failure mode:

  • In the selection: the rule goes quiet. file_event_win_exchange_webshell_drop requires CommandLine|contains: 'MSExchange' on a file event, so on unenriched Sysmon its selection is unsatisfiable and the rule never fires.
  • Handled deliberately: net_connection_win_susp_binary_no_cmdline carries the comment # e.g. Sysmon has no CommandLine field in network events with ID 3 and a null filter for that case. The dependency is real enough that the author tracked it by hand.
  • In a filter: the rule gets louder. create_remote_thread_win_susp_uncommon_source_image excludes known-good activity via TargetParentProcessId; the filter never matches on plain Sysmon, so the exclusions don’t apply and the rule fires more often than intended.

The rules are correct for the enriched pipelines they were written on. Which of them work on a given pipeline is a schema question, and schema questions can be answered in CI rather than during triage.

One detsema fix came out of the run: check used to claim a missing field “can never match” in all cases. For field: null tests the opposite holds (an absence test on a never-present field always passes), and the finding text now distinguishes the two.

Against the taxonomy’s field table

The 1,182 process_creation rules, checked against the table that defines their allowed field names:

Field Rules using it Emitted by Sysmon In the taxonomy table
OriginalFileName 580 (49%) yes no
Hashes 39 yes no (only the split md5/sha1/sha256/imphash forms)
ParentUser 2 yes no

Fix submitted: sigma-specification#215.

Reproduce

go install github.com/Big-Comfy/detsema/cmd/detsema@latest
git clone --depth 1 https://github.com/SigmaHQ/sigma /tmp/sigma
git clone --depth 1 https://github.com/OTRF/OSSEM-DD /tmp/ossem

# build a field list for process_creation (Sysmon event 1) from OSSEM
go run github.com/Big-Comfy/detsema/contrib/ossem2inv@latest \
  -ossem /tmp/ossem/windows/sysmon/events/event-1.yml \
  -source "OSSEM-DD sysmon event 1" -out proc_creation.json

detsema check --rules /tmp/sigma/rules/windows/process_creation \
  --schema proc_creation.json --format jsonl --fail-on never

Notes: rule directories are trusted to match their declared logsource categories (true in SigmaHQ). OSSEM-DD lags the newest Sysmon event types, so events 24-25 and 27-29 were declared by hand from Sysmon’s documentation. Without the envelope fields most pipelines add to every event (EventID, Provider_Name, Channel, Computer) the count is 23 findings rather than 19.