An emulated technique's auditd record exists and the rule matches it on replay, yet no alert reached the queue — where did it die?
answer
- matching by hand is not firing
- state at the time, not now
- event time versus index time
- suppression, dedup and routing
- search by rule id, widen the window
basics
~20 sBetween the rule matching and a human seeing it: the rule was disabled or in test mode, a scheduled search ran before the data was indexed, suppression swallowed the firing, or it was routed below the severity anyone reads.
solid answer
~50 sA hand-run query matching is not the same as the rule having run. Check, in order, what the rule's state was **at the time of the test** — enabled, in test or shadow mode, recently changed — then whether its schedule and lookback could have covered your record, comparing the event time with the time it was actually indexed, because a five-minute lookback misses a record that arrives twenty minutes late. Then search the alert store by rule identifier over a deliberately widened window, and the case system too: a suppression window from an earlier identical firing, a dedup key, an auto-close automation or a routing rule that filed it at informational severity all produce an alert nobody saw. If a worked ticket exists, the chain reached response and your finding stops there — whether the analyst's verdict was right is a triage review, not a purple-team output.
go deeper
Understand that a rule matching when you run its query by hand does not mean the rule was switched on or that anyone received its output.
Be ready to name the ways a firing disappears before a queue: disabled or test-mode rules, schedule and lookback windows, suppression and dedup, severity routing and auto-close.
Show the investigative order and the artefacts — rule state at the execution time, event versus index timestamps, an alert-store search by rule identifier across closed items.
Own the boundary: exercise findings name the link and hand off, because a report that grades individual analysts costs you the cooperation the programme depends on.
## Why "the query matches" is not "the rule fired" Re-running a detection's logic by hand over the stored record proves one narrow thing: the logic describes the behaviour. It says nothing about whether that logic was *executing*, *over the right data*, *at the right time*, or about what happened to its output. Everything between a match and a human is its own link, and on a mature platform it has more moving parts than the rule does. ## The branches, and the artefact that settles each **The rule was not live.** It was disabled, newly written and still in a test or shadow mode that produces no queue item, or it was edited after the exercise so that the version you replayed is not the version that ran. The evidence is the rule's change history and its enablement state stamped at the execution time — not its state now. This is the single most common answer and the easiest to overlook, because by the time you investigate, the rule looks perfectly healthy. **The rule ran, but not over your record.** Scheduled searches have a cadence and a lookback window, and records have an ingest time distinct from their event time. If your `execve` carried an event time of 03:00 but was indexed at 03:20 — batching, a backed-up shipper, a retry — then every scheduled run with a five-minute lookback stepped over it. The evidence is the two timestamps side by side against the search schedule. A related variant: the rule runs against a normalised index or data model that your record was never written into, so it is real, searchable and outside the rule's reach. **The rule fired and the firing was swallowed.** Deduplication and suppression exist to stop a noisy rule paging forty times, and they cannot tell your emulation from the noise. If the same rule fired on the same entity an hour earlier, your firing may have been folded into that group or dropped by a throttle window. Aggregation thresholds do the same thing: a rule that alerts only above N events in an interval will not alert on one deliberate execution — which is a genuine and interesting finding, because a careful intruder also acts once. **The alert exists but nobody sees it.** Routing sends it to a different tenant, index or queue; severity mapping files it as informational in a bucket that is never worked; or an automated enrichment rule closes it as expected activity. Note this last one carefully: an auto-close is a *response* failure that looks like an alerting failure, and the distinction matters because one team owns the routing and another owns the automation. **It reached a human.** There is a ticket, with a timestamp and a disposition. The chain worked all the way to the last link and the finding is now about what happened at that link. ## Search like the alert is there Search by **rule identifier**, not by the entity, and widen the window on both sides — an alert can be stamped with its detection time rather than the event time, and it can arrive well after the activity. Include closed and auto-closed items; the default queue view is the exact place a swallowed alert is invisible. Check whether the exercise itself was allow-listed: in many programmes the emulation source host, its user or its known payload hash sits in a suppression list from a previous exercise, and nobody remembered. ## Where your finding stops If you land on a worked ticket, write it as *alert produced, worked, not escalated* with the timestamps, and hand it on. Judging whether the analyst's verdict was defensible is a triage quality review with its own process and its own owner; a purple-team report that grades an individual analyst's decision loses the cooperation that the whole exercise runs on. Your job is to prove which link broke, and it broke at the last one. And keep the direction of the claim honest in the write-up: you have proved *this* rule did not produce a queue item for *this* execution in *this* window. You have not proved the platform drops alerts generally, and you have not proved anything at all about links you never exercised.
- How do you tell ingest lag from a genuine rule failure?Put the record's event time next to the time it was actually indexed, and both next to the search's schedule and lookback. If indexing landed after the last run that could have covered the event time, the logic was never given the data and the fix is the window or the pipeline, not the rule. If indexing was timely and the run happened, the failure is in the rule or its enablement.
- The alert exists at informational severity in a queue nobody works. Which link do you attribute?Alerting and routing. Collection and logic both worked and a human never had the chance to act, so the finding is about severity mapping and queue ownership, not about detection content. It is also a systemic finding rather than a per-rule one: ask how many other rules land in the same bucket.
- You find your emulation host in a suppression list from a previous exercise. What is the finding?That the exercise measured nothing. The result is void for that technique and must be re-run from a source that is not allow-listed. It is also a real finding in its own right: standing suppressions created for tests outlive them, and an adversary operating from that host or with that payload would be equally invisible.
saying these in an interview costs you the question
- Concludes the rule works because the query matches on replay
- Checks the rule's state now rather than during the test
- Searches only open alerts and misses auto-closed ones
- Ignores ingest lag against a short scheduled lookback
- Grades the analyst's verdict instead of naming the link