http: expose negotiated TLS key exchange in DSL metadata
Problem
Nuclei's HTTP protocol exposes useful TLS handshake and certificate metadata to DSL matchers,
extractors, workflows, and result events. This includes tls_version, cipher, sni, certificate
identity, validity, and fingerprints.
The completed tls.ConnectionState also contains CurveID, which Go documents as the key exchange
mechanism used for the connection, but enrichEventWithTLSMetadata currently discards it. As a
result, an HTTPS template cannot distinguish an observed X25519 handshake from
X25519MLKEM768, even though both can negotiate the same TLS 1.3 cipher suite.
TLSX already exposes this handshake fact as key_exchange, and Nuclei's SSL protocol maps
non-zero fields from the TLSX response into its event data. The HTTP and SSL protocol surfaces are
therefore inconsistent for the same connection property.
This is useful for cryptographic migration inventory, interoperability debugging, and TLS policy validation. It should be treated as observed handshake evidence, not as proof of every group a server supports.
Proposed solution
Add the negotiated group to HTTP TLS metadata using the existing TLSX field name:
if state.CurveID != 0 {
data["key_exchange"] = state.CurveID.String()
}This would make key_exchange available to the existing HTTP DSL and output path without another
request or TLS handshake.
Example extraction:
extractors:
- type: dsl
dsl:
- key_exchangeExample matching of the group selected by this probe:
matchers:
- type: dsl
dsl:
- 'tls_version == "tls13"'
- 'key_exchange == "X25519MLKEM768"'
condition: andSemantics
key_exchangeis the mechanism selected by the completed handshake, not the client's offered list or the server's full supported-group set;- omit the field when
CurveIDis zero or TLS state is unavailable; - preserve Go's
CurveID.String()representation so the HTTP field matches TLSX behavior; - do not infer
quantum_safe, compliance, vulnerability severity, or server-wide PQC support from this field alone; - do not change TLS configuration, connection reuse, redirects, or request count.
Implementation and verification
The focused change would:
- update
pkg/protocols/http/tls_metadata.go; - extend
TestEnrichEventWithTLSMetadatawith a classical group; - extend
TestResponseToDSLMapIncludesTLSMetadatato confirm DSL propagation; - add zero/unavailable
CurveIDcoverage; - cover
X25519MLKEM768where supported by the repository's Go toolchain; - document
key_exchangeas an SSL/HTTP response field where protocol field definitions are maintained; - add an integration fixture only if maintainers prefer it over the existing unit-level TLS state tests.
A detection or inventory template should be reviewed separately. In particular, a template must not label an observed classical selection as a vulnerability or conclude that the endpoint lacks hybrid support without controlled offer/enumeration semantics.
Related work:
- TLSX already emits
key_exchangefromConnectionState.CurveIDin itsctlsbackend. - open-telemetry/semantic-conventions#4015 proposes vendor-neutral attributes for negotiated TLS groups.
If this field parity is accepted, I can implement the code, tests, and documentation as a focused
PR based on dev.
Disclosure: I use OpenAI Codex as an engineering assistant and will review, understand, test, and take ownership of any submitted contribution. I also maintain related open-source PQC migration work and work through A2Z SOC, which provides scoped attack-surface cryptographic inventory and migration-readiness assessments. Any Nuclei code, tests, and documentation would remain vendor-neutral and contain no service promotion.
Source: projectdiscovery/nuclei