Suricata EVE JSON Log Fields: Reference With Examples
Published
One line of EVE JSON is one event from the Suricata sensor: a signature match, a parsed protocol transaction (HTTP, DNS, TLS), a flow summary or engine statistics, all sharing the same timestamp, flow_id and five-tuple header.
Sample record
{"timestamp":"2024-01-15T09:00:01.123456+00:00","flow_id":9000000001,"in_iface":"eth0","event_type":"http","src_ip":"203.0.113.10","src_port":52100,"dest_ip":"10.0.0.50","dest_port":80,"proto":"TCP","http":{"hostname":"api.example.com","url":"/api/v1/products","http_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36","http_method":"GET","protocol":"HTTP/1.1","status":200,"response_bodylen":4096}}
{"timestamp":"2024-01-15T09:00:05.234567+00:00","flow_id":9000000002,"in_iface":"eth0","event_type":"http","src_ip":"203.0.113.11","src_port":52101,"dest_ip":"10.0.0.50","dest_port":80,"proto":"TCP","http":{"hostname":"api.example.com","url":"/api/v1/users/42","http_user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15","http_method":"GET","protocol":"HTTP/1.1","status":200,"response_bodylen":512}} From the LogTriage parser test corpus — synthetic data, no real hosts or users.
Field reference
| Field | Type | Meaning | Why it matters for security |
|---|---|---|---|
| timestampe.g. 2024-01-15T09:00:01.123456+00:00 | datetime with offset | When the sensor recorded the event, to microsecond precision, with an explicit UTC offset. | The ordering key for reconstructing a session; the offset is the sensor's, so normalise before joining with other sources. |
| event_typee.g. http | string | What kind of event the line is — alert, http, dns, tls, flow, fileinfo, stats and others. | Decides how to read the rest of the line; alert lines are the only ones produced by a signature match. |
| flow_ide.g. 9000000001 | integer | Identifier Suricata assigns to the flow the event belongs to. | Joins an alert to the http, tls, dns and flow records of the same connection on that sensor. |
| src_ipe.g. 203.0.113.10 | IPv4/IPv6 | Source address of the packet or flow as seen on the monitored interface. | One external src_ip spread over many destinations or ports is scanning; an internal src_ip on a malware alert is a possible infection. |
| dest_ipe.g. 10.0.0.50 | IPv4/IPv6 | Destination address of the packet or flow. | Tells you which asset was targeted, or which external host an internal machine is talking to. |
| dest_porte.g. 80 | integer | Destination port. | Counting distinct dest_port values per src_ip within minutes is the core of port-scan detection. |
| protoe.g. TCP | string | Transport protocol of the flow. | Separates TCP service probing from UDP activity such as DNS queries and amplification. |
| app_protoe.g. failed | string | Application protocol Suricata detected on the flow; "failed" means protocol detection did not identify one. | Repeated "failed" values on short connections are typical of connect-only scans that never speak a protocol. |
| alert.signaturee.g. ET SCAN Potential SSH Scan | string | Human-readable message from the rule that matched. | The quickest triage field — the rule's own description of the behaviour it claims to have seen. |
| alert.signature_ide.g. 2001219 | integer | Numeric ID of the matching rule (the sid), with rev giving its revision. | Stable key for tuning, suppressing and counting the same detection over time. |
| alert.categorye.g. Attempted Information Leak | string | Classification text of the rule that matched. | Groups alerts into recon, web attack, malware command and control, and similar buckets for prioritisation. |
| alert.severitye.g. 2 | integer | Priority carried by the signature, where lower numbers are higher priority. | Reflects the rule author's view, not your asset's value — weigh it against what the destination host is. |
| alert.actione.g. allowed | string | Whether the packet was allowed or blocked by Suricata. | In IDS (passive) mode nothing is dropped, so "allowed" means the traffic reached the host and needs host-side confirmation. |
| http.urle.g. /api/v1/products | string | Request path and query string of the HTTP transaction, as sent. | Carries injection and traversal payloads verbatim, including spaces and quotes, so treat it as untrusted text. |
| http.http_user_agente.g. sqlmap/1.7.8#stable | string | User-Agent header sent by the client. | Tool strings such as sqlmap identify scripted attacks outright; absent or odd agents are worth a second look. |
| tls.snie.g. api.example.com | string | Server Name Indication the client asked for in the TLS handshake. | The only cleartext name in an encrypted session; compare it with tls.subject and with DNS records for the same flow. |
What it records
Suricata’s EVE output writes one JSON object per line. Each line is a single event from the sensor: a signature match (event_type of alert), a protocol transaction the engine parsed (http, dns, tls, ssh, smtp and others), a summary written when a flow closes or times out (flow), file metadata (fileinfo), or periodic engine statistics (stats).
Every event shares a common header — timestamp, flow_id, in_iface, event_type and the five-tuple src_ip, src_port, dest_ip, dest_port, proto — followed by one nested object named after the data it carries. An HTTP event has an http object with the hostname, URL, method, user agent and response status; a TLS event has a tls object with the subject, issuer, SNI and, when enabled, a JA3 hash; a flow event has byte and packet counts in both directions plus start, end, state and reason.
Alert lines add an alert object with action, gid, signature_id, rev, signature, category and severity, and often embed the protocol object for the transaction that triggered it — the SQL injection line in the malicious sample carries both the alert and the http details in one record.
Where to get it
EVE is configured in suricata.yaml under the eve-log output, which packages commonly write to /var/log/suricata/eve.json. The same output can be sent to a Unix socket, to syslog, or to a file that a shipper such as Filebeat, Fluent Bit or Vector tails into a SIEM. The types list in the configuration controls which event types are produced, so a sensor that logs only alerts gives you no HTTP, DNS, TLS or flow context to pivot into — enable the protocol and flow types before you need them.
Parsing pitfalls
- JSON Lines, not a JSON document. The file is newline-delimited objects with no surrounding array. Parsers that call a whole-file JSON load fail on the second line.
- The schema changes per line. The nested key is named after the event, so flattening the whole file produces a sparse union of
http.*,dns.*,tls.*,flow.*andalert.*columns. Branch onevent_typefirst. - Timestamps carry the sensor’s offset. They are microsecond precision with an explicit offset such as
+00:00; a sensor in local time will silently shift correlation with cloud logs. - One connection, many lines. An alert, the HTTP transaction and the closing flow record are three separate events. Counting lines overstates activity; count distinct
flow_idinstead. allowedis not a verdict.alert.actiondescribes what Suricata did, which in passive mode is always nothing.- Raw attacker text in fields.
http.urlandhttp.http_user_agentcontain whatever was on the wire, including spaces, quotes and--. Keep them as JSON strings rather than splitting on whitespace. - Addresses are as seen on the interface. Behind a load balancer or NAT,
src_ipis the last hop, not the client, unlessX-Forwarded-Forlogging is configured.
Detection ideas
- Port scanning: one
src_ipproducing alerts across many distinctdest_portvalues in seconds, usually withapp_protooffailedand ET SCAN signatures. - Web attack tooling:
http.http_user_agentofsqlmap/1.7.8#stableor similar, together with aWeb Application Attackcategory — and checkhttp.status, since a 200 on an injection attempt means the request was served. - Command and control: an internal
src_ipalerting on a malware category toward an externaldest_ip; pivot onflow_idto thetlsrecord and comparetls.sniwithtls.subjectand with the DNS query that preceded it. - Suspicious resolution: DNS events whose
dns.rrnameresolves to the same address an internal host later contacts on 443. - Volume anomalies:
flowevents with largebytes_toclientorbytes_toserveron a service that normally exchanges little data.
Where you also run Zeek, its connection and HTTP logs cover the same traffic without signature context and make a useful cross-check when a Suricata alert is ambiguous.
Frequently Asked Questions
- Why does alert.action say "allowed" on a malware alert?
- Because the sensor was not inline for that traffic. In passive IDS mode Suricata inspects a copy of the packets and can never drop them, so every alert records "allowed"; only an inline IPS deployment produces blocked actions. Treat an allowed malware or exploit alert as traffic that reached the host, and confirm on the endpoint.
- How do I tie an alert back to the HTTP request or TLS session?
- Use flow_id. Every event Suricata emits for the same connection — the alert, the http or tls transaction, and the closing flow summary — carries the same flow_id, so filtering on that one value reassembles the session. Combine it with the sensor identity and a time window rather than relying on flow_id alone across sensors.
- Is EVE JSON the same data as fast.log?
- No. fast.log is a one-line text summary of alerts only. EVE JSON carries the alerts plus the parsed protocol transactions, flow summaries, file metadata and engine statistics, which is why it is the output you want in a SIEM — the protocol records are what turn an alert into an investigation.
- What does app_proto "failed" mean?
- Suricata tried to identify the application protocol on the flow and could not. It shows up when a connection carries too little data to fingerprint, such as a bare TCP connect from a port scanner, or when traffic is on a non-standard protocol the parsers do not recognise.
Analyze Suricata logs
LogTriage auto-detects this format, enriches every IP, user agent and hash with threat intelligence, and writes an incident report mapped to MITRE ATT&CK.