Skip to content

NDJSON Schema Reference

This page describes the fields emitted in each offline NDJSON connection record.

The sniffer writes ECS-style JSON with a custom pqc.* namespace for quantum-safety and handshake details. Fields are omitted when the related protocol data was not observed or could not be parsed.

Record Shape

Each line is one complete JSON object:

{
  "@timestamp": "2026-05-11T18:40:13.141Z",
  "event": {},
  "source": {},
  "destination": {},
  "network": {},
  "observer": {},
  "pqc": {}
}

Protocol-specific objects such as tls, ssh, quic, and tcp are present only when that information is available.

Core Fields

Field Type Description
@timestamp string Event timestamp in ISO-8601 UTC format.
event.id string Connection identifier.
event.category array[string] ECS category; currently includes network.
event.type array[string] ECS event type; currently includes connection and protocol.
event.kind string ECS event kind; currently event.
event.dataset string Dataset name; currently pqc.network.
event.duration integer Connection duration in nanoseconds when available.
tags array[string] Optional tags, typically including the customer ID.

Conversation Fields

These are the fields most useful for top-talkers, port grouping, and address grouping.

Field Type Description
source.ip string Source IP address.
source.port integer Source transport port.
source.bytes integer Payload bytes observed from source to destination. Transport and network headers are not included, so a packet carrying no payload adds nothing.
source.packets integer Packets observed from source to destination, over the whole connection. Every captured packet in that direction is counted once, including those carrying no payload: TCP handshake, pure acknowledgements, FIN and RST. See Emission Rules for when the record is written, which is what makes these totals final.
destination.ip string Destination IP address.
destination.port integer Destination transport port.
destination.bytes integer Payload bytes observed from destination to source, counted as source.bytes is.
destination.packets integer Packets observed from destination to source, counted as source.packets is.
network.transport string Transport protocol, such as tcp or udp.
network.protocol string Application/protocol classification, such as tls, https, http/3, quic, ssh, dtls, ikev2, mqtt, smtp, smtps, dns-over-tls, dns-over-https, or http. See How the protocol is decided — read it with pqc.app_protocol_basis, which says what the classification was based on.
network.bytes integer Sum of source and destination bytes.
network.packets integer Sum of source and destination packets.
network.community_id string Optional community ID when available.
tcp.state string TCP state when tracked.
tcp.client_isn integer Optional client initial sequence number.
tcp.server_isn integer Optional server initial sequence number.

TLS Fields

These are also populated for DTLS connections (network.protocol = dtls), whose handshake has the same structure; for QUIC connections (quic or http/3), whose handshake is TLS 1.3 — see QUIC Fields; for SMTP sessions (smtp) upgraded with STARTTLS, from the handshake that follows the upgrade; and for NTS-KE sessions (nts), which are TLS 1.3 on TCP 4460. An SMTP session that stays plaintext has no tls object, and neither does an NTS-KE session first seen after its handshake.

Field Type Description
tls.version_protocol string Negotiated TLS version label: TLSv1.3, TLSv1.2, TLSv1.1, TLSv1.0, SSLv3, or Unknown.
tls.cipher string Negotiated cipher suite name when known.
tls.client.server_name string Client SNI value when present.
tls.next_protocol string Negotiated ALPN protocol when present.
tls.client_offered_pqc_kex string Comma-separated PQC KEX algorithms offered by the client when detected.
tls.established boolean Whether the TLS connection was established.

TLS Handshake Fields

TLS parser details are emitted under pqc.handshake.* so quantum-safety consumers can keep crypto evidence with the assessment.

Field Type Description
pqc.handshake.client_hello.version string ClientHello version.
pqc.handshake.client_hello.ciphersuites array[string] Client-offered cipher suites.
pqc.handshake.client_hello.compression_methods array[integer] Client-offered compression methods.
pqc.handshake.client_hello.supported_groups array[string] Client-offered supported groups/key-share groups, under the names the IANA TLS Supported Groups registry gives them, such as x25519 and secp256r1. A group the registry does not name is reported under the name this build knows it by, which for a post-quantum group is the OQS provider's, such as X25519MLKEM768. Anything else falls back to its hex code point.
pqc.handshake.client_hello.signature_algorithms array[string] Client-offered signature algorithms, under the names the IANA TLS SignatureScheme registry gives them, such as ecdsa_secp256r1_sha256 and rsa_pss_rsae_sha256. A scheme the registry does not name, which so far is every post-quantum one, is reported under the name this build knows it by, such as mldsa65. Anything else falls back to its hex code point.
pqc.handshake.client_hello.alpn_protocols array[string] Client-offered ALPN protocols.
pqc.handshake.client_hello.supported_versions array[string] Client-offered TLS versions.
pqc.handshake.server_hello.version string ServerHello version.
pqc.handshake.server_hello.selected_ciphersuite string Selected cipher suite name, or hex value if unknown.
pqc.handshake.server_hello.selected_alpn string Selected ALPN protocol.
pqc.handshake.server_hello.key_share.group string Selected TLS 1.3 key-share group.
pqc.handshake.server_hello.key_share.key_exchange_length integer Selected key-share length.
pqc.handshake.server_key_exchange.kex_type string TLS 1.0-1.2 key exchange type, such as ECDHE or DHE.
pqc.handshake.server_key_exchange.curve_name string ECDHE curve name when available.
pqc.handshake.server_key_exchange.public_key_length integer ECDHE public key length.
pqc.handshake.server_key_exchange.dh_p_length integer DHE prime modulus length.
pqc.handshake.server_key_exchange.dh_g_length integer DHE generator length.
pqc.handshake.server_key_exchange.dh_Ys_length integer DHE public value length.
pqc.handshake.key_exchange_algorithm string Parsed key exchange algorithm.
pqc.handshake.signature_algorithm string Parsed signature algorithm.
pqc.handshake.encryption_algorithm string Parsed encryption algorithm.
pqc.handshake.ciphersuite_name string Parsed cipher suite name.
pqc.handshake.client_offered_pqc_kex string PQC KEX algorithms offered by the client.
pqc.handshake.kex_quantum_safe string KEX component safety: Safe, Vulnerable, or Unknown.
pqc.handshake.sig_quantum_safe string Signature component safety: Safe, Vulnerable, or Unknown.
pqc.handshake.enc_quantum_safe string Encryption component safety: Safe, Vulnerable, or Unknown.

Changed in 2.1.0

Before 2.1.0 two offered signature algorithms were reported under OQS's names for them rather than the registry's: 0x0403 as ecdsap256 and 0x0804 as rsa3072. The second is the one to watch for in stored records: 0x0804 is rsa_pss_rsae_sha256 and carries no key size at all, so a record asserting rsa3072 stated a 3072-bit key the handshake never mentioned. Both now appear under their registered names. A query, dashboard or saved search matching either old value will stop matching; nothing else in this field changed, and no other field changed at all.

PQC Assessment Fields

Field Type Description
pqc.quantum_safety string Overall classification: Secure, Vulnerable, or Unknown. Note Secure, not Safe — the per-component *_quantum_safe fields above use Safe, this one does not. Unknown/unmapped TLS cipher suites or key-share groups produce Unknown rather than being treated as vulnerable classical crypto.
pqc.readiness_score integer Readiness score from 0 to 100.
pqc.has_pqc_kex boolean Whether the key exchange the server selected is post-quantum. Hybrids count. Not whether the client offered one — that is tls.client_offered_pqc_kex.
pqc.has_pqc_sig boolean Whether the signature algorithm the server selected is post-quantum. Always false on TLS 1.3, where the certificate is encrypted — see the note below.
pqc.pqc_kex_is_hybrid boolean Whether the PQC KEX is hybrid.
pqc.pqc_sig_is_hybrid boolean Whether the PQC signature is hybrid.
pqc.pqc_downgrade_detected boolean Whether downgrade behavior was detected.
pqc.app_protocol_basis string What evidence produced network.protocol: alpn, payload, port, or none. See How the protocol is decided.
pqc.pqc_kex_algorithm string Detected PQC KEX algorithm.
pqc.pqc_sig_algorithm string Detected signature algorithm — not only post-quantum ones, despite the name. See Where the signature algorithm comes from.
pqc.vulnerability_reason string Human-readable reason for a vulnerable or unknown classification. Always present when pqc.quantum_safety is Vulnerable.
pqc.assessment.overall_safety string Detailed overall assessment.
pqc.assessment.vulnerability_score integer Vulnerability score from 0 to 100. The inverse of pqc.readiness_score.
pqc.assessment.vulnerable_components array[string] Components contributing to vulnerability.
pqc.assessment.recommended_algorithms array[string] Suggested safer algorithms.
pqc.assessment.remediation_priority string Critical, High, Medium, Low, or None — see Remediation priority.

What the client offered and what the server chose are separate questions. The has_pqc_* booleans and the *_quantum_safe strings describe the connection that actually happened: they follow the server's selection, from the ServerHello key share and the certificate. What the client was willing to use is reported separately, in tls.client_offered_pqc_kex. The distinction is the point of the fields — a fleet whose clients already offer ML-KEM needs its servers upgraded, which is a different job from a fleet whose clients cannot speak it at all, and pqc.assessment.remediation_priority grades the two differently.

When the client offered a post-quantum key exchange and the server chose a classical one, pqc.pqc_downgrade_detected is true, pqc.has_pqc_kex is false, and pqc.handshake.kex_quantum_safe is Vulnerable. The offer is still recorded. Nothing about the client's capability raises the assessment of a session that did not use it.

pqc.has_pqc_sig and TLS 1.3

On TLS 1.3 the certificate is encrypted, so a passive observer never sees the server's signature algorithm. pqc.has_pqc_sig is false on every TLS 1.3 connection and pqc.handshake.sig_quantum_safe is Vulnerable. This is a limit of passive observation rather than a gap in parsing — the bytes are not on the wire to read. Take the field to mean "no post-quantum certificate was observed", not "the server does not have one".

On TLS 1.2 and earlier the Certificate message is in the clear and is parsed, so a post-quantum leaf certificate does set pqc.has_pqc_sig. That includes HSS/LMS, XMSS and XMSS^MT, which have no TLS SignatureScheme codepoint and so can never be named by the cipher suite. For the equivalent question on SSH, where the host key is always visible on the wire, use ssh.has_pqc_host_key.

These fields reported the client's offer before pqc-sniffer 2.0.1. pqc.has_pqc_kex and pqc.has_pqc_sig were set from the ClientHello, overwriting the verdict taken from the ServerHello, so any connection whose client merely offered post-quantum algorithms was published with has_pqc_kex true, pqc.handshake.kex_quantum_safe Safe and tls.quantum_ready_kx true — including downgrades, where the same record also set pqc.pqc_downgrade_detected and named a classical group. Because every OpenSSL 3.5 client offers ML-DSA by default, has_pqc_sig was true on ordinary RSA certificates. Separately, a classical TLS 1.3 connection carried no pqc.vulnerability_reason at all. Data collected before this release overstates post-quantum adoption; counts of has_pqc_kex are not comparable across the upgrade boundary. | pqc.assessment.assessed_at | string | Assessment timestamp in ISO-8601 UTC format. |

Where the signature algorithm comes from

pqc.pqc_sig_algorithm has two sources, and which one filled it depends on the TLS version.

From the cipher suite. On any handshake, the negotiated suite names an authentication method, and that is what the field carries: RSA from TLS_ECDHE_RSA_..., ECDSA from TLS_ECDHE_ECDSA_.... This is all a cipher suite can say, and it describes a method rather than the key the server actually holds.

From the server's leaf certificate. On TLS 1.2 and earlier, the certificate is sent in the clear, so the algorithm of the server's own key can be read directly out of it. This is the only way some algorithms can be seen at all: HSS/LMS, XMSS and XMSS^MT have no TLS codepoint and no cipher suite of their own — they exist only in certificates — so a server holding one of those keys negotiates an ordinary suite and would otherwise be recorded under whatever that suite's authentication field said.

The certificate value is used when it names a post-quantum algorithm, which a cipher suite could not have named, or when nothing else set the field. Otherwise the cipher-suite value stands.

Values are algorithm names where recognised — HSS-LMS, XMSS, XMSS-MT, ML-DSA-44/65/87, SLH-DSA-*, RSA, ECDSA, Ed25519 — and a dotted-decimal OID where not. An OID in this field is not an error; it means a certificate presented an algorithm newer than this release's table, which is worth knowing rather than discarding.

TLS 1.3 and QUIC never contribute a certificate-derived value. Both encrypt the Certificate message, so passive monitoring cannot read it. On those connections the field reflects the cipher suite alone, and a hash-based certificate is indistinguishable from any other. This is a limit of passive observation, not a gap in parsing.

How the protocol is decided

network.protocol is decided from the strongest evidence the handshake produced, and pqc.app_protocol_basis records which that was. The two should be read together: both a proven and a guessed classification say https, and only the basis separates them.

pqc.app_protocol_basis Meaning
alpn The TLS handshake negotiated an ALPN naming the protocol — h2 or http/1.1 for HTTPS, h3 (or a draft h3-NN) for HTTP/3. This is proof of what the tunnel carries.
payload Bytes on the wire matched a protocol signature — a request line beginning GET, or, on QUIC, the ALPN the client's ClientHello offered. An offer is an observation but not an agreement, which is why it is not alpn.
port TLS was present on a port that names the protocol by convention and no ALPN was negotiated: a port listed in connection_tracker.https_ports (https), or port 465 (smtps). This is inference, though see the note on 465 below.
none No classification evidence was recorded.

HTTPS is therefore no longer "TLS on port 443". Before this changed, that was the entire definition, so a web service on 8443 or 9443 was reported as tls however plainly it was HTTPS — and the negotiated ALPN, which the sniffer already parsed and publishes as tls.next_protocol, was consulted by nothing.

Two consequences worth knowing:

  • A negotiated ALPN that names a protocol other than HTTP (say imap) suppresses the port fallback. The handshake has stated what the tunnel carries, and a port number does not override an observation.
  • Setting connection_tracker.https_ports: [] disables the port tier entirely, so HTTPS is reported only where an ALPN proves it. That is the right setting if the inventory is being used as evidence rather than as a survey.

To exclude inferred classifications from a query, filter on the basis:

network.protocol="https" AND pqc.app_protocol_basis="alpn"

SNI is deliberately not used to classify. A hostname names the server the client intended to reach; it does not establish the protocol inside the completed tunnel, and after the handshake the sniffer cannot read HTTP requests to confirm.

DNS-over-HTTPS is the one exception, and it is worth being exact about what it means. A dns-over-https classification means the SNI matched a configured resolver hostname — not that DNS queries were observed. They cannot be: a DoH query travels inside the completed TLS tunnel, so the name the client asked for is the last thing a passive observer can read. The classification is kept rather than flattened into https because it is strictly more specific, and the tls.* and pqc.* fields beside it are measured from the handshake as usual.

Because it is a list of names, a resolver that is not on the list is reported as https. The default list covers the well-known public resolvers only, so a site running its own DoH endpoint should add it — see Identifying DNS-over-HTTPS resolvers.

SMTPS is kept for the same reason, decided from the port rather than from a name. Port 465 is implicit TLS for SMTP and is reserved for nothing else (RFC 8314), so TLS seen on it is smtps and is not flattened into tls. The basis is port, because a TLS handshake is present on a great many ports and the port is the part that discriminates. Unlike the https_ports inference, though, this one is not configurable and not a local convention, so it is the most certain of the port-based classifications rather than the least.

Only 465 qualifies. A TLS handshake on 25 or 587 is a session upgraded through STARTTLS, which keeps the smtp label from its plaintext phase and carries its tls.* fields from the handshake that followed the upgrade. A cleartext session on 465 stays smtp too, and has no tls object at all.

The whole pqc.assessment object is present only for connections that carried a cryptographic handshake the sniffer analysed. Cleartext traffic still gets pqc.quantum_safety: Unknown but no assessment, so ordinary unencrypted flows are not counted as outstanding remediation work.

Remediation priority

pqc.assessment.remediation_priority answers how much work is outstanding and how soon, which is a different question from is this quantum-safe. Two axes drive it.

Is the connection broken today, independently of quantum computers? A negotiated version of TLS 1.1 or older, or a cipher suite rated High or Critical by the intel database, outranks any amount of migration work and produces Critical on either safety classification.

How much of the migration is already done, which for a vulnerable connection is really a statement about who has to act.

Priority Emitted when
Critical Already weak by today's standards: a negotiated version of TLS 1.1 or older, or a cipher suite rated High or Critical by the intel database (CBC modes, 3DES, RC4, static RSA key exchange, SHA-1). Applies to quantum-safe connections too — PQC over TLS 1.0 is still broken.
High Quantum-vulnerable, and neither end advertised post-quantum support. Both the client fleet and the server need upgrading: the largest job, and the most common tier on a network that has not started migrating.
Medium Quantum-vulnerable, but the client advertised PQC algorithms and the negotiation stayed classical without a downgrade being flagged. Partial readiness on one side. Also used when a handshake was analysed but could not be classified at all.
Low Either a detected downgrade — the client offered PQC and the server declined it, so one server-side configuration change closes it — or a quantum-safe connection that is not finished, such as hybrid key exchange or PQC on only one side of the handshake. The smallest remaining work in both cases.
None Fully post-quantum on both key exchange and signature. Nothing to do.

The tiers are ordered by remaining effort, not by how alarming each sounds. A detected downgrade is Low because the endpoint fleet already speaks PQC and only the server needs changing — it is the cheapest item in the vulnerable population, not the least serious one. A downgrade that warrants investigating as an active attack is surfaced separately through pqc.handshake.downgrade_detected and the Active Threat and Anomaly Detection dashboard.

All four of Critical, High, Medium and Low are reachable by vulnerable connections alone. This matters because every panel on Vulnerability Analysis is filtered to pqc.quantum_safety: "Vulnerable", and its four priority KPIs are documented as summing to the vulnerable count — a tier that required Secure could never appear there.

The cipher rating that drives Critical is the same one published in the same record under tls.handshake.server_hello.cipher_suite_intel.overall_risk, so a priority can always be traced to the field that produced it. An unrecognised cipher suite does not escalate — a missing intel row is a gap in the database, not evidence of weakness.

The priority is deliberately not banded from pqc.readiness_score as a severity proxy. That score measures PQC migration maturity only: it awards points for offering and selecting post-quantum algorithms and knows nothing about TLS version, cipher strength, or certificate size. A TLS 1.0 / RSA-1024 / CBC connection scores 0, and so does a healthy TLS 1.3 / X25519 / ECDSA-P256 connection, because neither involves PQC. Banding on the score would rank those two identically.

Generating one connection per tier, for validating a dashboard against live traffic:

Critical  openssl s_server -tls1 -cipher AES128-SHA
High      openssl s_server -tls1_3 -groups X25519, client with no PQC support
Medium    client with -groups X25519MLKEM768:X25519 against a classical-only server,
          where no downgrade is flagged
Low       client with -groups X25519MLKEM768 against a server without the OQS provider
          (downgrade), or a hybrid X25519MLKEM768 handshake with a classical certificate
None      hybrid or pure PQC key exchange with an ML-DSA certificate

SSH Fields

Field Type Description
ssh.client.protocol_version string Client SSH protocol version.
ssh.client.software_version string Client SSH software version.
ssh.client.comments string Optional client banner comments.
ssh.client.kex_algorithms array[string] Client-offered SSH KEX algorithms.
ssh.client.host_key_algorithms array[string] Client-offered SSH host key algorithms.
ssh.server.protocol_version string Server SSH protocol version.
ssh.server.software_version string Server SSH software version.
ssh.server.comments string Optional server banner comments.
ssh.selected_kex_algorithm string The key exchange algorithm the two ends negotiated — the client's highest preference the server also supports.
ssh.has_pqc_kex boolean Whether the negotiated key exchange is post-quantum. Hybrids such as mlkem768x25519-sha256 count.
ssh.kex_quantum_safe string Safe when ssh.has_pqc_kex is true, Vulnerable otherwise.
ssh.selected_host_key_algorithm string The host key algorithm the server authenticated with.
ssh.has_pqc_host_key boolean Whether that host key is a post-quantum signature algorithm — ML-DSA, SLH-DSA or FN-DSA, under those names or the Dilithium/SPHINCS+/Falcon names they shipped under.

Key exchange and host key are separate questions. ssh.has_pqc_kex describes the KEM that protects the session; ssh.has_pqc_host_key describes the signature that authenticates the server. A connection can be post-quantum in one and classical in the other, and today most are: OpenSSH has shipped post-quantum key exchange since 9.0 and offers no post-quantum host keys at all, so has_pqc_host_key is normally false even on an otherwise modern handshake. Harvest-now-decrypt-later risk follows the key exchange; forgery risk follows the host key.

These algorithm fields were absent or wrong before pqc-sniffer 2.0.1. SSH handshake analysis stopped after the version banner, one TCP segment before the algorithms arrived, so the four list and selection fields were never written and ssh.has_pqc_kex was always false with ssh.kex_quantum_safe always Vulnerable — including on connections that had negotiated a post-quantum key exchange. ssh.has_pqc_host_key and ssh.selected_host_key_algorithm were never emitted at all. Connections whose key exchange never parsed were also dropped without producing a record at all, so SSH is under-represented in data collected before this release. Comparisons across the upgrade boundary will show both more SSH connections and more of them quantum-safe; neither is a change in the estate.

QUIC Fields

Field Type Description
quic.version string Parsed QUIC version.

A QUIC connection's handshake is reported in the same tls.* and pqc.* fields as TLS: the negotiated cipher suite and key-exchange group, the client's offered groups and key shares, and the quantum-safety verdict. The sniffer reads it from the connection's first packets (QUIC "Initial" packets), which QUIC encrypts with keys any observer can derive, including a ClientHello split over several packets, as post-quantum key shares make it.

Some QUIC records have no tls object:

  • The flow was first seen after its handshake, for example because it was already running when capture started. Its record is written after 60 seconds with what was observed.
  • The connection uses QUIC version 2 (RFC 9369), whose first packets are not read.

The negotiated ALPN is not observable on QUIC: TLS 1.3 sends the server's selection in EncryptedExtensions, which no passive observer has the key for. The ALPN the client offered is observable, because it travels in the Initial packets the sniffer already decrypts, and it is read — so a QUIC flow offering h3 is reported as http/3 with pqc.app_protocol_basis of payload, on any port, rather than being named after port 443.

An offer is weaker evidence than an agreement and is not presented as one. It is acted on only when every token in it names the same protocol: a client offering ["h3", "h3-29"] is HTTP/3 whichever the server picks, while a client offering ["h3", "h2"] leaves the choice to a ServerHello that cannot be read, so that flow keeps the port classification and its port basis. HTTP/3 is a classification, not a parse — the HTTP/3 frames themselves travel in QUIC streams encrypted with keys an observer cannot derive, so no HTTP/3 request detail appears in a record.

HTTP/3 before 2.0.1

http/3 meant "QUIC on UDP port 443" and nothing more, with pqc.app_protocol_basis of port. HTTP/3 on another port was reported as quic.

QUIC before 2.0.1

QUIC records never carried handshake fields. The first packets were never decrypted, so QUIC connections, including browsers' post-quantum X25519MLKEM768 sessions, were reported without a key exchange or a quantum-safety verdict.

IKE Fields

Present on IKEv2 connections once the cleartext IKE_SA_INIT exchange has been seen. Every later IKE exchange is encrypted, so this is all an observer can learn about the SA.

Field Type Description
ike.offered_key_exchanges array of strings Key exchange methods the initiator offered, including RFC 9370 additional key exchanges, e.g. ["Curve25519", "ML-KEM-768"].
ike.key_exchange string The negotiated key exchange: the KE method, then each additional key exchange joined with +, e.g. Curve25519+ML-KEM-768. Absent until the responder's choice is seen.
ike.encryption string Negotiated encryption transform, with key length, e.g. AES-GCM-16-256.
ike.prf string Negotiated pseudorandom function, e.g. HMAC-SHA2-256.
ike.integrity string Negotiated integrity transform. Absent with AEAD ciphers such as AES-GCM, which need none.

An IKEv2 SA is reported quantum-safe when the negotiated key exchange includes ML-KEM, either as the key exchange method itself or as an additional key exchange; pqc.pqc_kex_is_hybrid tells the two apart. When ML-KEM was offered but the responder chose a classical exchange, pqc.pqc_downgrade_detected is true and pqc.vulnerability_reason says so.

IKEv2 before 2.0.1

IKEv2 records carried no algorithm at all, IKE behind NAT traversal (UDP 4500) was not identified, and the post-quantum check recognised ML-KEM only under unregistered private-use codepoints — so a genuine ML-KEM SA would have been reported as classical.

MQTT

Plaintext MQTT (network.protocol = mqtt) has no key exchange to assess: the finding is that the session is unprotected. Its records carry pqc.quantum_safety = Vulnerable and a pqc.vulnerability_reason naming the MQTT version and whether the CONNECT sent a username or password in cleartext. The credentials themselves are never read or recorded. MQTT over TLS (usually port 8883) is reported as TLS.

Observer Fields

Field Type Description
observer.name string Sniffer ID/name.
observer.type string Observer type; currently sniffer.
observer.vendor string Vendor name; currently Tychon.
observer.product string Product name; currently Automated Cryptography Discovery & Inventory (ACDI) Sniffer.

Dashboard Notes

For top-talkers grouped by port, address, and KEX method, use:

  • Port: destination.port, with source.port available for client-side grouping.
  • Address: source.ip and destination.ip.
  • Conversation count: count records or unique event.id values, depending on the aggregation window.
  • KEX method: prefer pqc.handshake.key_exchange_algorithm; fallback to pqc.handshake.server_hello.key_share.group for TLS 1.3 key-share group detail.
  • Safety: use pqc.quantum_safety for the overall connection classification.