Skip to main content

Tuning a detection rule

Exactly which parts of a shipped rule your organisation may change, which parts it may not, how to make the change, and what the change does to your risk scores.

Written for whoever runs IT9 min readUpdated

The shipped detection library is tuned for a typical small business, and your business is not typical in at least three ways you already know about. Tuning is how you close that gap: you leave the rule in place and adjust the numbers, rather than switching off a class of visibility.

This article covers what you may change, what you may not, the exact procedure, and the two coupling effects that surprise people. It assumes you have read The detection library, because the parts you are about to adjust are described there. Everything below is about a stream rule — the always-on shape. A separate, scheduled rule shape now also exists, wrapping the same detection logic on a cadence rather than continuously; see Scheduled detection rules and templates if that is what you are trying to tune.

What you may change

The nine tunable settings, what each does, and the sensible reason to reach for it.
SettingWhat it doesWhen to use it
enabledSwitches the rule off for your organisation entirely.Almost never. Read the section on disabling below before you use this.
statusSets draft, testing, active or disabled for your organisation. testing is shadow mode — evaluated, feeds risk, raises no alert.Moving a rule to testing is the good version of switching it off. You keep the finding and the risk contribution and lose only the interruption.
severityinformational, low, medium, high or critical.When a pattern genuinely carries less consequence in your estate than in a typical one. Read the coupling warning below first.
risk_scoreThe 0-100 weight this rule contributes to an entity's accumulated risk.When you want to change what a rule contributes to incidents without changing how its alerts are ranked, or the reverse.
thresholdHow many matching events inside the window are needed.The first thing to reach for on a noisy count-based rule. Raise it before you consider anything else.
min_eventsA persistence floor — a minimum number of events regardless of the threshold arithmetic.When a rule fires on a genuine but trivially small burst you do not care about.
timewindow_secThe length of the aggregation window, in seconds.When your business rhythm is slower or faster than the default assumed. A longer window catches a patient attacker and also more legitimate activity.
cooldown_secHow long the rule stays quiet for the same entity after firing.When one real event produces a stream of near-identical alerts. Lengthening the cooldown is much safer than raising a threshold, because you keep the detection at full sensitivity.
suppressionsA list of field-and-values exclusions applied before the rule is evaluated.The precise tool for a named, legitimate cause. Covered in Suppressing a false positive.

There are also two free-text fields: notes, which persists on the override so the next person can see what you were doing, and reason, which is recorded on the audit entry for that specific write. They are not the same field and they are not interchangeable — notes is the current state of your intent, reason is the history of how it got there.

What you may not change

Everything that constitutes the detection itself is fixed: the identifier, the title, the description, the MITRE mappings, the selections, the condition expression, the group-by fields, the distinct-count field, the listed data sources, the false-positive guidance, the response actions, the risk entity kinds and the provenance.

That boundary is where it is on purpose. A tenant-editable condition expression is a tenant-editable detection, which means we can no longer tell you what your coverage is, the contract test that keeps the counts honest no longer applies to you, and a rule you broke in March looks identical to a rule that is working. If a shipped rule's logic is wrong for your estate, that is a conversation to have with us — see How to get help — not a field to edit.

Grouping is on that list, and it is the one people expect to be tunable. What a shipped rule counts separately by — per user, per host, per source address — is part of its shipped definition and cannot be changed for your organisation. You can change how many, how long and how loud: the threshold, the window, the cooldown and the severity. You cannot change what the counting is grouped into. Choosing the grouping is something you do when you write a rule of your own from scratch, which is a different path — see Testing a rule before you trust it.

Two specific refusals are worth naming:

  • You cannot set a rule to deprecated. Only the four statuses above are accepted from a tenant. The request is rejected with status "deprecated" cannot be set by a tenant override.
  • A deprecated shipped rule stays off whatever you ask. If we have deprecated a rule, enabling it does nothing — the effective rule comes back disabled regardless. The definition is no longer maintained, and honouring your enable would ship unmaintained detection logic into your production estate.

The two coupling effects

The second coupling is between status and enabled, and it is simpler. Setting status also sets whether the rule is enabled — anything other than disabled enables it. An explicit enabled in the same request then wins over that. In practice: send one or the other, not both, unless you have a specific reason.

Most people should do this from the console, not the API below

Everything from here down is the raw API, worth knowing because it is what the console itself calls and because it is the only path for a scripted change. But the console's rule editor — Detection → Rules, open any rule — is a no-code editor with four numbered sections: what it detects (the MITRE techniques and required fields, each marked as available or pending for your tenant), when it fires (severity, threshold, time window and cooldown, as dropdowns and steppers, not JSON), exceptions (per-field suppressions, built the same way described below), and a live replay panel that runs the rule against your own recent events and tells you how many times it would have fired before you publish anything. If you have never tuned a rule before, start there — the JSON shape below is for the person who already knows exactly which field to change and wants to script it.

One detail of that screen is worth knowing before you go looking for a control that is not there. The at least this many events setting — min_events in the table above — is conditional: it only appears when the rule is also counting distinct values of a field. On a rule that is not, the when it fires section simply does not show it, because a persistence floor has nothing to be a floor against. That is correct behaviour rather than a missing control, and it is the reason two rules can present a different number of settings on the same screen.

How to make the change through the API

  1. Check you have the permission

    Reading rules needs siem:rules.read; changing one needs siem:rules.write. These are separate on purpose, because the tuning endpoints can disable an organisation's detections — see Roles and permissions. If the rule endpoints are not visible to you at all rather than returning a permission error, that is deliberate too: they are mounted only when the permission checker is available, because an ungated mount would be worse than no mount at all.

  2. Read the rule, including the false-positive guidance

    GET /api/v1/organizations/{orgID}/siem-detection-rules/{ruleRef}, where {ruleRef} is the stable identifier such as NES-SIEM-100. The response deliberately puts the tuning knobs and the false-positive guidance side by side, because the guidance is what tells you which knob to turn. It also shows the threshold rationale — the reason the shipped number is the number — and pending_fields, which tells you whether the rule is quiet because of missing telemetry rather than because of anything you did.

  3. Find the rule if you do not know its identifier

    GET /api/v1/organizations/{orgID}/siem-detection-rules lists them, and accepts ?status=, ?tactic= (matching either the tactic id or its name, case-insensitively), ?data_source= and ?enabled=true. Filtering by data source is the quickest way to answer what have I got for the logs I actually send.

  4. Decide the smallest change that fixes the problem

    In descending order of preference: add a narrow suppression on the specific innocent cause; lengthen the cooldown; raise the threshold; move the rule to testing; lower the severity. Disabling is last, and it is a different kind of decision from the others.

  5. Send the override

    PUT /api/v1/organizations/{orgID}/siem-detection-rules/{ruleRef}/tuning with a JSON body. Every field is optional. Unknown fields are rejected outright rather than ignored, so a typo in a field name is an error rather than a change that silently did nothing. The body is capped at 64 KiB, which in practice bounds how long a suppression list can be. A successful write answers 200 with {"rule_ref": "NES-SIEM-100", "tuned": true}.

  6. Always send a reason

    It is mandatory when you are disabling a rule — omit it and the request fails with a reason is required when disabling a detection rule. It is optional everywhere else and you should send it anyway. Who turned off the ransomware rule, and why is a question asked after every incident, and an empty audit row cannot answer it.

  7. Wait half a minute, then verify

    Effective rules are cached per organisation for 30 seconds, because re-reading the whole library plus your overrides from the database on every batch of events would put a query in front of every event. So a tuning change takes up to 30 seconds to take effect. If you test immediately and see the old behaviour, wait and test again before concluding the change did not save.

  8. Check the coverage view afterwards

    GET /api/v1/organizations/{orgID}/siem-detection-coverage reports your total rules, how many are enabled, how many can actually alert, the breakdowns by severity, tactic and data source, your ATT&CK technique and tactic coverage, and how many rules are blocked on telemetry you do not send. Read it after a tuning session, not before — it is the honest answer to what you have just done to your own coverage. Shadow-mode rules are counted separately from alerting rules there, because a coverage view that counts them as coverage is a coverage view that lies.

To undo everything you have set on one rule, DELETE the same /tuning path with a ?reason= query parameter. That removes the whole override and returns the rule to shipped defaults, answering {"rule_ref": "NES-SIEM-100", "tuned": false}. There is no way to clear one knob with the delete; to clear a single setting, send a PUT that omits it, because an omitted field clears that part of the override. That is what reset this one knob has to mean.

Every write is audited

Each tuning write records an actor and a reason alongside the change. Suppression entries carry their own individual reason as well, so a suppression list stays reviewable rather than becoming a pile of exclusions nobody remembers agreeing to.

Disabling, and why it is the wrong first move

Disabling a detection is a control change, not a preference. The rule stops evaluating, the finding stops being recorded, and the risk contribution stops accumulating. Nothing about your console afterwards indicates that a category of activity has become invisible — which is precisely the problem, because the absence of alerts from a disabled rule is indistinguishable from quiet.

Almost every case where somebody wants to disable a rule is better served by one of three alternatives. Move it to testing, and you keep the finding and the risk contribution and lose only the interruption. Add a suppression on the specific innocent cause, and you keep the rule at full sensitivity everywhere else. Lengthen the cooldown, and one real event produces one alert instead of forty.

The right time to tune anything is a scheduled hour on a quiet day with the false-positive guidance open in front of you. The wrong time is during an incident, when the pressure is to make the noise stop and the noise is sometimes the point.

When tuning is unavailable

Tuning needs the rule catalog in the database. The catalog is seeded on boot — idempotently, version-gated so an unchanged library is a no-op, and validated before write, so a library that fails validation aborts the seed rather than storing a rule that cannot fire. If that seed fails, the failure is deliberately non-fatal: the compiled library still evaluates, so a database problem degrades your ability to tune rather than degrading detection itself.

What you will see in that state: the read endpoints still work and return the shipped defaults, and any attempt to write an override answers 503 with rule tuning requires a configured database. That is a platform problem rather than something you have misconfigured; report it rather than retrying.

The other errors are ordinary validation, returned as 400 with the message in an error field. The ones you are most likely to meet:

Validation messages from the tuning endpoint
a reason is required when disabling a detection rule
status "deprecated" cannot be set by a tenant override
unknown severity "severe"
risk_score 140 is outside the 0-100 band
threshold must be positive
min_events must be positive
timewindow_sec must be positive
cooldown_sec may not be negative
suppression 0: field "metadata.username" is not in the event field contract
suppression 1: at least one value is required

A 404 with rule not found means the identifier does not exist — check for a transposed digit, and remember that identifiers are sparse, so NES-SIEM-111 never existed rather than having been removed.

What to read next

  1. Suppressing a false positive — the narrow tool, used properly.
  2. Shadow detections, and why some rules stay quiet — before you promote a rule out of testing.
  3. Alert severity, and what a match actually means — what severity is actually asserting, before you change one.
  4. Scheduled detection rules and templates — the second, cadence-based rule shape.

Was this article wrong?

If a procedure here does not match what you see, or a limit we described has changed, tell us and we will fix the page. Email us about this article, or see how to get help if you need an answer rather than a correction.

Everything in logs and detection