Sigma Rule Tester
Run a Sigma rule on JSON logs. See which events fire and why.
How the tester works
The page parses the rule with a YAML parser, compiles each search identifier into matchers, inlines them into the condition and evaluates every event. Matching follows the Sigma specification: case-insensitive unless the rule says |cased, wildcards * and ?, backslash escapes, and arrays in the log fan out so any element can match.
- Lint before you ship. Errors stop the rule: unknown or misspelled modifiers (the |contain and |regex that AI drafts invent), undefined identifiers, filters swallowed by 1 of them, regexes that do not compile. Warnings cover metadata, ATT&CK tags, unused selections and field names that do not exist in the CloudTrail, Okta, GitHub or Windows process creation schema.
- Score it. Events labelled
"_expect": "match"or"nomatch"become test cases, so a rule change shows its effect on caught attacks and false positives at once. The samples are labelled this way. - Structured alerts. Each hit exports as JSON with the rule, ATT&CK techniques, extracted entities (user, IP, host, process, account), the identifiers that matched and the evidence fields. That shape is what an automated investigation pipeline or a SOAR playbook reads.
- Lint and Convert tabs. The Lint tab lists every finding and applies the safe automatic fixes. The Convert tab writes the rule as Splunk SPL, Sentinel KQL, Elastic Lucene and Athena SQL, the same output as the Sigma Converter. Each tab has its own link: #test, #lint or #convert.
- SigmaHQ pack. The page recognises CloudTrail, Okta, GitHub audit, Entra ID, Google Cloud audit and Windows process creation logs, downloads every SigmaHQ rule for that source and runs them all. Attack events that no rule catches are your coverage gaps.
How it compares
The engine is checked against SigmaHQ's own rules and regression samples, and its features against the open-source tools that match Sigma on logs.
| Measure | Before this pass | Now |
|---|---|---|
| SigmaHQ rules that parse and compile | 3,791 of 3,791 | 3,791 of 3,791 |
| SigmaHQ regression samples that pass (SigmaHQ runner rule) | 471 of 471 | 471 of 471 |
| |exists: yes and no read as booleans | No | Yes |
| |neq modifier | Lint error | Yes |
| Correlation rules and filters in matching | Refused | Yes, sliding windows |
| EVTX JSON (evtx_dump, Chainsaw) on paste | Nested fields missed | Flattened |
| Feature | pwnsy tester | Zircolite 4.7.1 | Hayabusa 4.3.1 | Chainsaw 2.17.1 |
|---|---|---|---|---|
| Runs in the browser, logs stay local | Yes | No (viewer only) | No | No |
| Log input | JSON, NDJSON, EVTX as JSON | EVTX, JSON, CSV, XML, Auditd | EVTX, JSON | EVTX, JSON, XML |
| Correlation rules (Sigma 2.0) | event_count, value_count, temporal, temporal_ordered | All eight types | Four types | count() only |
| Sigma filters | Yes | Not documented | Not documented | No |
| Modifiers | All but |expand | pySigma set | Full list in docs | No cidr, exists, fieldref, cased, utf16 |
| Precision scoring on labelled events | Yes (_expect) | Rule test cases | No | No |
| Lint with autofix | Yes | No | No | Lint only |
Known limits
- Regression samples are Windows and Sysmon only. Cloud sources are covered by the round trip on the Convert tab.
- |expand placeholders (34 SigmaHQ rules) need values the page does not have, so those rules never match.
- Correlation windows slide from each matching event. Splunk and KQL output uses fixed bins, which can split a burst.
- No binary EVTX reader. Export with evtx_dump or Chainsaw first.
Sigma tester FAQ
Are my logs or rules uploaded?
No. The Sigma engine runs in this page. The only network calls fetch SigmaHQ rules from jsDelivr or GitHub when you search for one or run the pack.
How do I score precision on my own logs?
Add "_expect": "match" to events the rule should catch and "_expect": "nomatch" to benign look-alikes. The page then counts caught attacks, misses and false positives. The engine ignores the _expect key when matching.
Which Sigma features are supported?
The Sigma 2.0 detection format: field maps and lists, keyword lists, wildcards and escapes, null and empty values, the modifiers contains, startswith, endswith, all, re with i, m and s, cased, exists, neq, cidr, gt, gte, lt, lte, fieldref, windash, base64, base64offset and the utf16 encodings, and conditions with and, or, not, brackets, 1 of, all of and them. Correlation rules (event_count, value_count, temporal, temporal_ordered) and filters run when you paste them with their base rules, separated by ---. EVTX exported as JSON is flattened on paste. The deprecated count() pipe and |expand placeholders are reported as unsupported.
Why does my rule match nothing?
Open an event row. It lists each search identifier as true or false and the fields the rule reads that the event lacks. The usual causes are a field name that differs from the raw log, a value that needs a contains modifier, or a filter that is included by 1 of them.
What does the SigmaHQ pack run do?
It recognises the log source, downloads every SigmaHQ rule for it and runs them all against your events. You see which community rules fire, on which events, and which labelled attack events no rule catches.
Sample logs on this page are made up and use documentation IP ranges. SigmaHQ rules are fetched live from github.com/SigmaHQ/sigma under the Detection Rule License 1.1. Engine checked against 415 SigmaHQ cloud, identity, GitHub and Windows rules, October 2026.