HackBlue

Tools · Network IDS and detection as code · 08 / 24

Suricata: stop tuning and write the false positive

Stop adding exceptions when the next one would widen past a single known source. Leave the rule in place and write the false positive on the remaining alerts.

11 min read · practice only with authorization

An exception names one source

A tuning entry is justified when it names one stable source: one address, one sensor, or one exact DNS name, plus who accepted it and when it expires. The rule still matches everyone else. That is a narrow edit, and it belongs in the rule repository with the reason on the same lines.

Count how many such entries the signature already has. Each one is a place the signature no longer speaks. The list is part of reading the output, because an alert you do not see may have been removed by an entry rather than by quiet traffic.

The request that should be refused

The request to stop is the one that replaces a single source with a subnet, a whole VLAN, or “any host that looks noisy.” That entry would also hide a match from a host that should still alert. Exit the tuning change. Do not lower the rule’s severity to make the queue shorter, and do not delete the signature to finish the ticket.

Width is the test. If you cannot point at one source that is supposed to match, you do not have an exception. You have alerts that need a written disposition.

What you write instead

On each remaining alert, record the signature id and revision, the field that matched, why this source is expected to match, who accepts that noise, and the date the acceptance ends. The rule stays loaded, so a new source still produces a row. The written false positive is how a reader sees why these particular rows were not paged.

When the acceptance date passes, the rows are in scope again. The writing does not silently renew.

Worked case: a subnet that would swallow the lab

Signature 1000302 matches lookups of status.hackblue-lab.org. Two exceptions already exist: the monitor at 10.8.0.8 and the resolver’s own check from 10.8.0.53, each with an owner and an expiry. Workstations also look the name up hourly because the lab image does. The next request is to except 10.8.0.0/24.

That request is refused. A workstation that started looking the name up for a new reason would disappear with the rest of the subnet. The finding instead lists the workstation rows as false positives: signature 1000302 rev 4, query name status.hackblue-lab.org, expected hourly lookup from the lab image, accepted by net-ops through 2027-01-15. The signature continues to alert for any address outside the two existing exceptions and outside that written list.

Snippet
sid 1000302 rev 4
matched: dns query name status.hackblue-lab.org
source: 10.8.0.40
disposition: false positive
why: hourly lookup baked into the lab image
accepted by: net-ops
until: 2027-01-15
rule change: none

Diagram

Another exception versus a written false positive

Widen the silence only when one source is still the whole story.

Add a wider exception

Scope. A subnet, or every noisy host

Effect. New sources inside that scope vanish

Use when. You should not

Write the false positive

Scope. The rows you already listed

Effect. The rule still matches everyone else

Use when. The next exception would be wider than one source

Check yourself

1. Which proposed exception should you refuse?

2. After you refuse that wider entry, what happens to the signature?

3. Why put an end date on the written false positive?