Collecting logs is the easy part of security monitoring. Most organizations already send endpoint, identity and cloud telemetry to a SIEM. The harder part is turning that data into a small number of alerts that are correct, explained and acted on.
Detection engineering is the discipline that does this. It treats each detection as a piece of software with a purpose, an owner, tests and a maintenance history. This article walks through the practice, with a worked example in Kusto Query Language (KQL) for Microsoft Sentinel.
Detections managed as code
A detection rule edited directly in a console has no history. Nobody can say who changed the threshold, why an exclusion was added, or what the rule looked like before it stopped firing. Managing detections as code fixes this with ordinary software practice.
- Version control. Each rule lives in a repository as a file: the query, severity, schedule, entity mapping, ATT&CK mapping and analyst notes. Sentinel analytics rules can be exported as ARM templates and deployed from a repository. Sigma is a common platform-independent format.
- Review. Changes arrive as pull requests. A second engineer checks the logic, the exclusions and the expected volume before anything reaches production.
- Tests. Each rule has at least one sample event that must match and one that must not. A pipeline validates syntax, runs the tests and deploys to the workspace.
The benefit shows during an incident review. When someone asks why a behavior was not detected, the repository answers with a commit, a reviewer and a reason.
The detection lifecycle
A detection moves through a repeatable set of stages. Skipping stages is how rules end up noisy or silently broken.
- Hypothesis from a technique. Start with a specific behavior, for example "an attacker runs PowerShell with an encoded command to hide what it does". Sources include ATT&CK, threat research, incident findings and penetration test reports.
- Data source check. Confirm the telemetry exists, contains the fields you need, covers the devices that matter and arrives with acceptable delay. Many detection ideas end here, and that is a useful finding in itself.
- Write. Build the query against real data. Start broad, look at what matches, then narrow.
- Test against simulated behavior. Execute the technique in a test environment and confirm the rule fires. Open test libraries such as Atomic Red Team help. Findings from penetration testing and purple team exercises are better still, because they reflect your own environment.
- Deploy. Release at low severity, or without incident creation, first. Watch the volume for a week or two before the rule pages anyone.
- Tune. Add narrow exclusions with a recorded reason. Adjust severity based on what analysts found.
- Retire. Remove rules whose data source has gone, whose technique is covered better elsewhere, or that have never produced a useful result. A retired rule stays in the repository history.
Using MITRE ATT&CK without treating coverage as a score
ATT&CK gives detection teams a shared vocabulary. Mapping each rule to a technique and sub-technique makes it possible to ask where the gaps are, and to prioritize the behaviors relevant to your sector and technology.
The risk is that the coverage map turns into a target. A colored cell says that a rule exists with that label. It does not say the rule works, that it covers more than one variant of the technique, or that the data source reaches every host.
Techniques also differ in breadth. Command and Scripting Interpreter can be carried out in a great many ways, and one rule does not cover it. Some techniques are barely visible in logs at all and are better handled by preventive controls.
A more honest map records depth for each technique: how many distinct procedures are detected, whether each rule was validated by simulation, and when it was last tested. Use it to plan work. Do not report it upward as a single number.
Worked example: encoded PowerShell commands
Hypothesis. Attackers pass PowerShell a Base64-encoded command so that the command line is unreadable to a casual observer and to simple keyword matching. This maps to ATT&CK T1059.001, PowerShell.
Data source. Microsoft Defender for Endpoint process events, available in Sentinel as the DeviceProcessEvents table. Organizations that run the Microsoft security stack usually receive this table through the Defender XDR connector. The check: are all servers and workstations onboarded, and does ProcessCommandLine arrive populated?
Query.
DeviceProcessEvents
| where Timestamp > ago(1h)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| where ProcessCommandLine matches regex @"(?i)\s[-/]e(c|n[codeman]*)?\s+[A-Za-z0-9+/=]{40,}"
| where not(InitiatingProcessFileName in~ ("ccmexec.exe", "monitoringhost.exe"))
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
The regular expression does two things. PowerShell accepts abbreviations of -EncodedCommand, so the pattern matches -e, -ec, -enc and the longer forms without matching -ExecutionPolicy. It then requires a Base64-looking string of at least 40 characters, which removes short arguments that happen to follow -e.
The two excluded parent processes are illustrative. Management agents such as Configuration Manager and monitoring tools legitimately launch encoded PowerShell, and your list will differ. In a scheduled analytics rule the lookback is set in the rule's schedule settings, so the time filter here mainly serves interactive use.
Test. On a test device, run PowerShell with an encoded harmless command such as Get-Date and confirm a result. Add variants to the test set: -enc, the full parameter name, a forward slash prefix, and pwsh.exe. Record what the rule misses, such as a Base64 argument wrapped in quotes or a renamed PowerShell binary, as known gaps or as the next iteration.
Handling false positives without hiding true ones
Every exclusion is a place where activity goes unseen. The aim is to remove known benign activity as narrowly as possible.
- Exclude on a combination of fields. A parent process name alone is weak, because a file can be renamed. Parent name plus folder path, signer or a specific command line pattern is much harder to imitate.
- Prefer decoding to excluding. Decode the argument and alert on what the command does. PowerShell encodes the command as UTF-16LE, so a plain Base64-to-string function does not return readable text directly. Handle the byte order in the query or in an enrichment step.
- Keep exclusions reviewable. Store them in a watchlist or a file under version control, each with an owner, a reason and a review date.
- Adjust severity instead of suppressing. An encoded command in an interactive session on a finance workstation and one on a build server are different events. Device and account context can raise or lower severity.
- Track outcome history. If analysts keep closing results as benign for the same reason, that reason belongs in the logic.
When a rule is too noisy to alert on but still valuable, keep it as a hunting query. It can also run as a low-severity signal that contributes to an incident only when it coincides with other alerts on the same device.
What the analyst needs to receive with the alert
A detection is finished when the person receiving it at three in the morning knows what to do. Write the following into the rule description or a linked runbook, and review it in the same pull request as the query.
- What the rule detects and why it matters, in two sentences, with the ATT&CK technique.
- Known benign causes, such as software deployment tools, and how to recognize them.
- First triage steps. For the example above: decode the command, check the parent process and the user, then look for network connections and file writes by the same process in the following minutes.
- Escalation criteria. The evidence that turns this into an incident, for example a decoded command that downloads content or disables security tooling.
- Response options and who may authorize them, such as device isolation.
- Entity mapping for the account, host and process, so the platform can group this alert with others.
This documentation is what lets a managed SOC or an in-house team handle the alert consistently across shifts. It also exposes weak detections. If you cannot write the triage steps, the rule is not ready.
Where to start
- Export your existing analytics rules into a Git repository, one file per rule, and make pull requests the only route to production.
- Add an owner, an ATT&CK mapping and a short analyst note to each rule as you touch it.
- Pick five techniques relevant to your environment, simulate them in a test environment, and record which rules fired.
- Set a monthly review of the noisiest and the quietest rules. Tune the first group, and test or retire the second.
