Entity Extraction
Entities drive correlation, enrichment and response targets, so they must be correct,
typed, and normalized. Validate every value with prompt-injection-defense rules.
Field paths
| Entity | Wazuh field paths (check in order) | Typical role |
|---|---|---|
| ip | data.srcip, data.src_ip, data.win.eventdata.ipAddress, data.aws.sourceIPAddress, data.office365.ClientIP, data.gcp.protoPayload.requestMetadata.callerIp | attacker (source) |
| ip | data.dstip, agent.ip | victim |
| host | agent.name (+ agent.id), data.win.system.computer, predecoder.hostname | victim |
| user | data.dstuser, data.win.eventdata.targetUserName | victim |
| user | data.srcuser, data.win.eventdata.subjectUserName, data.aws.userIdentity.arn, data.office365.UserId, syscheck.audit.user.name (FIM who-data) | attacker or observed |
| process | data.win.eventdata.image, data.win.eventdata.parentImage, data.win.eventdata.commandLine, data.audit.exe, data.command, syscheck.audit.process.name (FIM who-data) | observed |
| file | syscheck.path, data.win.eventdata.targetFilename | victim/observed |
| hash | syscheck.md5_after, syscheck.sha1_after, syscheck.sha256_after, data.win.eventdata.hashes, data.virustotal.source.sha1 | observed |
| domain | data.url host part, data.win.eventdata.queryName, data.dns.question.name | observed |
Windows hashes fields look like SHA256=…,MD5=…: split and type each.
Wazuh puts extra metadata next to these values: agent.ip is the agent's registered
address (NAT'd hosts all show the same one), manager.name is the Wazuh manager (never
an entity), and location is the log source (file path or channel), not a host.
Rules that interpolate fields into rule.description (e.g. rule 87105 VirusTotal with the
file path) repeat attacker-supplied values. Extract from the structured field, not the
description.
Normalization
- IPs: strip ports (
1.2.3.4:22→1.2.3.4), drop IPv6 zone ids, lowercase IPv6. - Hosts: lowercase; keep FQDN if present; always include the Wazuh
agent.idin enrichment so responders can target it. - Users: keep domain prefix (
CORP\alice→ valuecorp\alice); lowercase. - Hashes: lowercase hex; type by length (32 md5, 40 sha1, 64 sha256).
- Domains: lowercase, strip trailing dot.
- Files/processes: keep full path; don't normalize case on Linux.
Roles
attacker— the entity performing the suspicious activity (source IP of brute force, user who ran the malicious command).victim— the entity acted upon (target host, targeted account, modified file).observed— related but role unclear (a process in the tree, a hash seen).
Private (RFC 1918 / loopback / link-local) source IPs are attacker only if the
evidence supports it; otherwise observed. Loopback is never an attacker.
Caps and dedup
- Max 50 entities per type per update; dedupe by (type, value).
- Keep counts in
enrichment.countand first/last seen timestamps when known.
Entity object
json{"type": "ip", "value": "203.0.113.7", "role": "attacker", "enrichment": {"field": "data.srcip", "count": 42, "first_seen": "...", "last_seen": "...", "private": false}}
For hosts add "agent_id": "001" inside enrichment.
Output
add_entities(case_id, entities)with validated, normalized objects.- If values were rejected or truncated,
add_findingtitledEntity extraction noteslisting what was dropped and why.


