Rule syntax 1.0

Rule syntax

آخر تحديث 10 نوفمبر 2026
في هذه الصفحة

Every key of a rule, every modifier, and the rules of thumb that keep a detection precise.

The keys

Key

Required

Meaning

id

yes

<PREFIX>-<NAME>, the prefix being the module's. Unique.

module

yes

The module that runs it (signal list).

severity

yes

critical, high, medium or low, by the severity criteria.

title

yes

One line.

evidence

yes

The evidence types it reads.

detail, impact, focus

yes

What happened, why it matters, what to do next - about one match. {count} is replaced by the number of matches.

text

no

Different wording per evidence type: {"running_process": {"focus": "..."}}.

condition

yes

The selections combined with and, or, not and parentheses.

detection

yes

Named selections, each mapping fields to a matcher.

min_count

no

Fire only once this many events matched (default 1).

entity

no

The entity type its signals are about, when not the record's own subject.

coalesce

no

Fields whose values make one signal.

tags

no

ATT&CK technique IDs.

notes

no

For the rule's authors; not shown with signals.

tests

yes

The fidelity contract. See Testing.

disabled

no

true keeps the rule in the file without running it.

Matchers and modifiers

JSON
{"field.name": {"modifier": "endswith", "values": ["\\a.exe", "\\b.exe"]}}

Modifier

Matches when the field

equals (or none)

is exactly a value

contains, startswith, endswith

contains, starts with, ends with a value

in_folder

is a path whose folder ends with a value: \temp matches ...\Temp\x.exe, not ...\Temp\setup\x.exe

token_prefix_of

has a whole word, written as a switch (-, / or a Unicode dash), that is a prefix of a value, 3 characters at least: -enc for encodedcommand, but not -ExecutionPolicy

switch

has a whole word that is exactly -value or /value - for short aliases like PowerShell's -e

Matching ignores case. Booleans are matched as "true" / "false".

One signal, many matches

  • By default, a rule's matches with one subject are one signal.

  • Give coalesce when the subject is too broad: a shell's matches are different signals by command line - "coalesce": ["process.name", "process.command_line"].

  • Give entity when the record's subject is the wrong thing: an IFEO rule's signal is about the hijacked program, not the debugger - "entity": "program".

  • Never coalesce on a time or a record number: every match would be its own signal.

Raw log records

security_event and system_event are raw records: "this record is in the Security (or System) log". One event ID means different things from different providers in one log - on one real host, 84 of 99 System events 104 came from a smart-card driver, and only 15 were log clears.

Write rules that cannot be fooled

  • Match a file name whole: \\cmd.exe, not cmd.exe, which mycmd.exe also ends with.

  • Match what an attacker cannot choose. A name ending in $ is not proof of the computer's account - a hidden local account can end in $. The system's logon session 0x3e7 is.

  • Anchor path exclusions at the drive: :\program files\, never \program files\ anywhere - an attacker chooses the path.

  • Select what you mean. For unsigned code, file.signature equals [unsigned, invalid, not found] - never not (equals valid), which also matches a file nobody could check.

  • Match a service's program on service.program (the path without arguments), never on service.image_path, whose arguments can name any folder.

  • Avoid localised words. Service start types and states may be written in the host's display language; built-in rules do not match them.

Naming attack tools in rules

A rule may name an attack tool or its syntax where the detection needs it. But a plain .json file that names a tool can be quarantined by an antivirus. Pack it:

PowerShell
signal rules -pack -rules C:\signal-rules

This writes a compressed .pack beside each .json; -rules reads either. Keep the .json as your source. Packing is not secrecy: signal rules prints the rules in full.