Behavioral baselines: what the comparison is actually against

“Baselining” only means something once you can say what the baseline is and what it is compared against. This page is the mechanism behind five shipped changes to Cernity’s behavioral analytics: per-entity fingerprint novelty, capped signal families in risk scoring, visibility-weighted confidence, beacon periodicity that survives missed callbacks, and replay-safe aggregates. For the narrative version, see the baselines story.

Two of these changes exist because we went looking for ways the detector could be wrong and found them: one was delivering findings at full confidence while the sensor that produced them was degraded, and one was manufacturing a data-transfer finding out of double-counted bytes. Every change below is described with the behavior it replaced, because the replaced behavior is what tells you what the current one is actually doing.

Thresholds and warm-up spans are deployment configuration. This page names the behavior each setting controls rather than quoting a default that your deployment may not use.

1. Per-entity fingerprint novelty

What is measured. When a client opens a TLS connection, the shape of its handshake yields a JA4 client fingerprint. Novelty is scored against that source entity’s own fingerprint history, not against a single set for the whole deployment. Fleet rarity is a separate input: it counts how many distinct entities have ever presented a fingerprint, not how many events carried it. So a fingerprint that is ordinary on servers elsewhere is still a change on a workstation that never spoke it before.

Before this change there was one fingerprint set per deployment, so a fingerprint counted as novel only if nothing anywhere had ever presented it. A workstation that started speaking a Go or Python TLS stack already used by some server produced nothing, a fingerprint shared by browsers and malware was permanently trusted, and the warm-up was small and short-lived enough that the baseline never matured — which re-alerted on the same benign fingerprints on a rolling daily cycle.

What the finding carries. The fingerprint, the entity it is new to, the fleet-rarity context (distinct entities that have presented it), and whether the result was adjusted. Two adjustments exist:

  • A fingerprint that is new to the entity but a close variant of one it already speaks lowers the result, as evidence of a benign client update rather than a new program.
  • A standalone “new to this entity” result is informational by design. A browser point-release, a new VPN client and a software rollout all look exactly like it, so it escalates only with a corroborating signal.

A second detector, deliberately separate. Per-fingerprint novelty cannot see an entity cycling through many fingerprints, because each individual fingerprint may be unremarkable. A separate detector scores an entity presenting many distinct fingerprints in a short window — randomized impersonation — over the same handshake stream.

How it is configured. By the readiness behavior: a baseline is learn-only until it has both enough observations and enough elapsed time, so neither condition alone promotes it out of learning. The previous warm-up was small and short-lived enough that baselines never matured, which is what produced the rolling daily re-alerts on benign fingerprints.

Where the boundary is. Learn-only means a newly seen or low-traffic entity produces no fingerprint finding at all, and reports “still learning” instead of guessing. That is a real blind spot on exactly the entities most likely to be newly planted. It is reported rather than hidden, and silence from it must be read as missing coverage, not as a clean result. A JA4 does not identify a program, device, person, malware family or adversary — see enrichment for what fingerprint naming does and does not assert, and coverage boundaries for the sensor-side prerequisites.

2. Capped signal families in risk scoring

What is measured. Each detector that contributes to an entity’s risk belongs to a signal family: fingerprint, temporal, destination, volume, DNS, or signature. Each family’s contribution to the total is capped.

This matters because several shipped detectors read the same underlying behavior from different angles: a periodic callback keyed by destination IP and the same callback keyed by resolved domain; two overlapping long-connection measures; a high-connection-count measure over the same series; several DNS measures over one query stream; client and server handshake rarity on one handshake. The score previously added all of them as if they were independent evidence, so one behavior could post five contributions and trip the incident threshold alone.

What the property buys. No single behavior, however many detectors describe it, can alone trip an incident — while two genuinely independent behaviors still can. That is the whole design goal; it is not a general reduction in sensitivity.

What the incident carries. The per-family breakdown, so an analyst can see which behavior was capped rather than only a smaller total.

How it is configured. By the detector-to-family map and each family’s cap. A detector that is not in the map keeps its previous weight, so adding the map did not silently remove influence from anything.

Where the boundary is. A cap changes how much one behavior can contribute to a risk total. It is not a measurement of detector accuracy. Per-detector precision and false-positive rate come from analyst dispositions and are reported separately — see detection coverage and quality.

3. Visibility-weighted confidence

What was already right. Cernity already detected a sensor dropping packets at capture or gone blind to the application layer, and raised a separate health finding for it, so “no findings” was never read as “no threat”. That part — surfacing the gap at all — was the hard half, and it shipped first. See fleet management for the health telemetry and packet visibility for where in the flow it is measured.

What was missing. Findings produced during a degraded window went out at full confidence, as if the view had been perfect.

What is measured now. The service that measures sensor visibility publishes its verdict on every measurement, including recovery, and the verdict is applied at the single point where every candidate becomes a finding — so there is one place to reason about, not one per detector.

Three rules the implementation turns on. Each is worth stating because each is a way this feature could have been dishonest and is not:

  • “Not measured” is not “healthy.” An unmeasured sensor’s findings are left untouched, and a stale measurement decays toward unknown rather than toward good.
  • Severity is never changed — only confidence. Degraded visibility can therefore never quietly move a real finding out of delivery or below a severity gate.
  • Nothing is silently rewritten. The original confidence, the factor applied, and the reason codes are all kept on the finding, so an analyst can see the adjustment and undo it mentally. See reading the records for how confidence should and should not be interpreted.

How it is configured. By two behaviors, neither of which is a verdict you dial up: the freshness of a visibility measurement — past the point where a measurement is no longer current it decays toward unknown, never toward good, and an unmeasured sensor is left alone — and the field the verdict is allowed to touch, which is confidence and only confidence. There is no setting by which degraded visibility changes severity, and none by which “not measured” becomes “healthy”.

Why it cannot be abused. The same service that raises the health finding publishes the quality verdict. Confidence can therefore only ever be discounted for a sensor that is simultaneously raising a health alert — a broken sensor cannot be made to look secure by discounting its findings into silence.

Where the boundary is. This makes a degraded window legible; it does not make the coverage complete. A discounted finding is still a finding, and the packets the sensor never saw are still missing. Absence claims need a defined search scope and a functioning collection path.

4. Beacon periodicity that survives missed callbacks

What is measured, primarily. A periodic callback is scored first on the regularity of its inter-arrival intervals, using outlier-robust statistics. This remains the primary measure.

Why it needed a fallback. The interval measure degrades when callbacks go missing — a laptop asleep, a dropped packet, a network outage — because a skipped beat turns one gap into one interval at twice the period, and a distribution measure reads that as irregularity rather than as a gap. A one-in-three drop rate alone was enough to push the score below its own firing threshold.

What is measured as the fallback. When the interval measure does not fire, periodicity is re-checked by autocorrelating a binned event series — asking whether the connections line up with themselves one beat later. A missed beat is then a missing sample rather than a wrong interval, and the beats that did arrive still line up.

What the finding carries. Which method produced the result, and the period it recovered.

How it is configured. By the gate: the fallback is consulted only when the primary interval measure does not fire, so it can recover a beacon the interval statistics missed but never overrides them where they hold.

Where the boundary is — two things, not buried:

  • Autocorrelation finds a dominant period. It does not prove command-and-control: schedulers, update checks and health probes are periodic too. That is precisely why it is a fallback behind the primary measure rather than a detector of its own.
  • It is not a general answer to jitter. Randomizing each sleep interval walks the beacon’s phase out of step with itself, so past roughly ±50% per-interval jitter the correlation decays along with it, and the robust interval statistics often serve that case better. The jitter problem is not solved.

5. Replay-safe byte and connection aggregates

The bug, plainly. Suricata reports a connection’s byte count as a running total — “100 MB so far”, then “500 MB so far”, then “900 MB so far”. Cernity was adding those together, so a connection that moved 900 MB could be counted as 1,500. And because the message bus delivers at least once, a service restart re-read records it had already counted and added them a second time.

Cernity flags a large enough outbound transfer as possible exfiltration. So ordinary backup traffic was inflated past that line and a false “someone is taking your data” finding was manufactured. The duplicate-suppression then worked perfectly, which made it worse: the output was one clean, confident, entirely wrong alert. That is the worst shape a false positive can take, and it is the reason this is documented rather than quietly patched.

What is measured now. The accumulating counters are gone. Each connection’s latest running total is stored against that connection’s own identity, and the total is summed when the threshold is checked. Two properties follow directly:

  • Reading the same record twice changes nothing — redelivery is idempotent.
  • A later running total replaces the earlier one for that connection, so interim records cannot stack.

The same shape applies to the other cumulative Suricata counters used this way, including connection counts and cumulative session time.

What the finding carries. The total as evaluated at the threshold check, and — when the cap below binds — an explicit floor marker with the count of omitted updates.

How it is configured. The number of distinct connection identities retained per destination has a ceiling, so memory does not grow without bound on a high-fan-out pair.

Where the boundary is. When that ceiling binds, the reported total is a floor, published with the count of omitted updates attached. It is never silently truncated and must not be read as the exact figure. See the evidence plane for retrieving the underlying observations behind an aggregate.

Boundaries, collected

If you read only one section, read this one.

ChangeThe boundary you must hold
Per-entity fingerprint noveltyLearn-only until a baseline is ready. A newly seen or low-traffic entity produces no finding and reports “still learning”. Silence is missing coverage, not a clean result.
Capped signal familiesCaps limit one behavior’s contribution to risk. They do not measure precision, recall, or false-positive rate.
Visibility-weighted confidence“Not measured” is never treated as healthy, and severity is never changed. Legibility of a degraded window is not completeness of coverage.
Beacon autocorrelation fallbackFinds a dominant period, not command-and-control. Decays past roughly ±50% per-interval jitter; the jitter problem is not solved.
Replay-safe aggregatesWhen the per-destination identity ceiling binds, the total is a floor with omitted-update count attached, not the exact figure.

A JA4 fingerprint does not identify a program, device, person, malware family or adversary. None of these five changes establishes general precision, recall, throughput, or superiority to equivalent SIEM analytics — see what the published records can support.

Not available yet

Related work that is roadmap, listed here so it is not mistaken for any of the above. Consistent with the capability roadmap, these are not shipped and not available:

  • Durable multi-week baseline history.
  • Day-of-week and time-of-day seasonality in baselines.
  • Role-based peer cohorts for fingerprint comparison.
  • Baseline poisoning defense.
  • Replacing the public-suffix handling used in domain analysis.

Where to go next

← All documentation