[[ fm.text ]] Click here

How Rule Validation Works

What the messages on a rule's page actually mean — the difference between a rejected rule and a valid rule with room to improve, and a catalog of the most common ones.

What is validated, and when

Every supported format (YARA, Sigma, Suricata, Zeek, Wazuh, NSE, CRS, Nova, KQL, Splunk, Elastic, ...) implements its own validate(content) — the same contract, one plug-in per format, documented in rule_type_abstract.py. It runs at three moments:

1
On submission — pasting a rule, importing from JSON/ZIP, or a GitHub import/sync. A rule that fails validation here is never created — it's filed as a bad rule instead, with the exact errors attached, so it can be reviewed and fixed.
2
On every visit to a rule's detail page — its current content is re-validated live (cheap, stateless, nothing is stored). This is what powers the alert boxes at the top of the page — always reflecting the content as it is right now, not whatever it looked like when it was first created.
3
When computing the Quality Score — a related but separate check, documentation_signals(content), which each format also implements. See below.

Errors vs. warnings

validate() returns two separate lists, and a rule's page shows them as two visually distinct boxes — mixing them together used to make a routine documentation suggestion look like the same kind of problem as genuinely broken content, which this page (and that distinction) exists to fix.

errors

Required identity or logic fields are missing, malformed, or hold a value outside a short, fixed set (a status enum, a UUID shape, a risk-score range, ...). A rule with any error is not created at submission time — it becomes a bad rule instead. Seeing this on an already-existing rule's page means the format's validator was tightened after that rule was imported (e.g. a GitHub sync brought in older or looser content) — worth reviewing and fixing.

Shown as: "Rejected pattern present"
warnings

Everything the format considers good practice but not mandatory — an optional field, a recommended structure, an ID that doesn't quite look right. A rule with only warnings is accepted exactly as submitted — nothing is blocked or rejected. It mainly affects the rule's Quality Score and how easy it is for someone else to review/reuse.

Shown as: "Format & documentation suggestions"

Common warning messages

Every format has its own wording, but almost all of its warnings fall into one of these families:

Missing recommended field: X An optional-but-conventional field for this format — author, references, how_to_implement, known_false_positives, rule.false_positives, rule.note, rule.setup, analytic_story, and similar — is empty or absent. These fields don't change what the rule does; they document why it exists, how to deploy it, and what to expect from it, which is exactly what the next person reviewing or reusing the rule needs. This directly feeds the documentation portion of the Quality Score.
'<id>' doesn't look like an ATT&CK technique/tactic ID A MITRE ATT&CK identifier was found but doesn't match the expected shape (T1059, T1059.001 for a technique, TA0002 for a tactic). It's kept as-is — nothing is silently corrected — but it likely won't be recognized by the ATT&CK matrix/auto-tagging. Worth double-checking the ID against attack.mitre.org.
Missing or empty rule.threat / mitre_attack_id / analytic_story No ATT&CK mapping or campaign grouping was found at all. Some formats (Splunk, Elastic) group individual detections into a broader "story"/campaign for easier discovery — this flags a rule that stands alone with no such grouping. Not required, but it's how someone browsing by technique or by campaign would ever find this rule.
Structural hints (e.g. Splunk's type 'TTP' normally requires a 'finding' block, Sigma's query-pipe check, NSE's luac not found/Missing action() function) Format-specific best practices — a detection type that usually pairs with a particular metadata block, a query shape that looks incomplete, a script missing the entry point its engine expects. Each of these is documented in that format's own adapter (app/features/rule/rule_format/available_format/) and reflects a convention from that format's own upstream project, not a Rulezet-invented rule.
None of these block anything. A rule with ten warnings and zero errors is just as usable, searchable, and testable as one with none — it simply scores lower on documentation completeness.

Common error messages

Missing or empty required field: X A field every rule of this format must have to even be meaningfully identified or executed — a title/name, the actual detection logic (search, query, a YARA rule block, ...), a description. Without it, the rule can't be reliably titled, searched, deduplicated, or run.
'<value>' is not one of: [...] A field is restricted to a short, fixed set of values by that format's own specification — a status, a severity, a query-language identifier, a rule category — and the value found isn't one of them. These enums are only hard-enforced when they're small and stable; large or evolving catalogs (ATT&CK technique IDs, story names, tags) are never hard-enforced this way, since that would reject legitimate rules that simply use a value outside this project's own knowledge of the format.
rule_id/id must be a valid UUID, got: ... The format expects a UUID as its own external identifier and what's there doesn't match that shape (wrong length, invalid characters, ...). This is used for cross-referencing the rule to its upstream source and for duplicate detection — a malformed one usually means a typo in the original file itself.
TOML/YAML/XML parse error: ... The content isn't even syntactically valid in the format's own file format — a structural typo (unclosed quote/bracket, bad indentation, ...) that prevents parsing the rest of the rule at all.

How this affects the Quality Score

Separately from validate(), each format also implements documentation_signals(content) — a small checklist of whether the rule documents its references, false positives, implementation notes, and ATT&CK mapping. A missing signal there is exactly the kind of thing a Missing recommended field warning above is telling you about — fixing the warning is generally how a rule's documentation-completeness score goes up.


Corpus-wide checks (Suricata datasets & flowbits)

One check is genuinely about interference between rules rather than a single rule's own content: Suricata rules can reference a shared dataset filename or a flowbit/xbit/hostbit name that other, independently authored rules also read or write. Two rules silently disagreeing about the same resource name can crash the detection engine at load time or corrupt each other's state. This is checked once, at submission time only (not re-run on every page view like the per-rule warnings above), and surfaces as its own rejection/warning right when a conflicting Suricata rule is submitted.

Together with the false-positive gate below, these are the only two checks that look beyond a single rule's own content — everything else on this page is about one rule in isolation.

False-positive gate & risk tag proposals

The other corpus-wide check, reachable from Tags → Rule Validation, is entirely separate from validate() and doesn't run on submission — it's a deliberate, on-demand admin action powered by rulezet-validation: every rule is scanned against a corpus of known-clean binaries, and any rule that fires on one is quarantined — a concrete false-positive risk, demonstrated against real files rather than inferred from the rule's own text.

1
Quarantine — a rule that matches one or more known-clean binaries is flagged, with the exact hit count kept alongside it.
2
Propose a risk level — purely from that hit count (20+ clean binaries is high, 5-19 medium, 1-4 low; a rule quarantined with no hits on record is cannot-be-judged, never guessed as "low"), in the exact vocabulary of the MISP false-positive taxonomy already available as tags here (false-positive:risk="high", etc.).
3
Compare against the rule's own claim — if the rule already carries a false-positive:risk tag of its own, both values are shown side by side. Agreement needs no action; a disagreement between what a rule says about itself and what was actually observed is the case most worth a reviewer's attention, and is surfaced first.
4
Accept, or don't — a proposed tag is never applied automatically. Accepting it (one rule at a time, or several at once from the same rule browser used everywhere else on the site) tags the rule; leaving it alone changes nothing.
A run's full history (including its complete log) stays available afterward — nothing about it needs to be re-run to look at it again.