{"id":"GHSA-w44r-93j7-qv28","revision":null,"records":[{"revision":"812e481551714eefa3d03301fc51f6bc","observedAt":"2026-10-27T16:45:46.193+00:00","statement":{"source":"osv","id":"GHSA-w44r-93j7-qv28","aliases":["RUSTSEC-2026-0349"],"title":"rustls: An unauthenticated ServerHello poisons the per-name key-exchange record, so later ClientHellos carry only a classical X25519 share","description":"## Summary\n\nThe client records the server-selected key-exchange group per server name when it processes the ServerHello, before the server is authenticated. A network attacker can answer one connection attempt for a target name with a ServerHello that selects X25519 and close the connection. Later ClientHellos for that name carry one X25519 share while supported_groups still lists X25519MLKEM768 first. If the server accepts that share instead of sending a HelloRetryRequest, the handshake completes with classical key exchange only and no error.\n\nAn attacker that answers one connection attempt for the target name with a ServerHello selecting X25519 changes every later ClientHello of that client for that name, for as long as the entry stays in the store. No certificate or completed handshake is needed: it parses the ClientHello, sends the ServerHello, and closes.\n\nTLS 1.3 transcript binding stops an on-path attacker from editing the ClientHello of one connection. It does not stop the attacker from steering the client's prediction state beforehand, because that state is written from an unauthenticated message.\n\n## What does not trigger it\n\n- Servers that send a HelloRetryRequest. The connection stays hybrid and costs one extra round trip.\n- A client configuration with resumption disabled: nothing is stored.\n- A different server name: the record is per name.\n\n## Impact\n\nIf the genuine server picks the group for which a share is present, instead of sending a HelloRetryRequest for its preferred hybrid group, the handshake completes with classical key exchange only, between two peers that both support the hybrid group. No error is raised. The confidentiality of recorded sessions against a future quantum adversary is lost for those connections (harvest now, decrypt later). There is no key compromise and no authentication bypass.\n\nNote that this behaviour is discussed at length in [draft-ietf-tls-key-share-prediction](https://www.ietf.org/archive/id/draft-ietf-tls-key-share-prediction-01.html#name-security-considerations) so the actual security impact is largely down to a server policy decision.","state":0,"publishedAt":"2026-10-27T16:08:54+00:00","modifiedAt":"2026-10-27T16:15:05.3403471+00:00","affected":[{"ecosystem":"crates.io","name":"rustls","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"0.23.46"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"crates.io","name":"rustls","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0.24.0-dev.1"},{"kind":"fixed","version":"0.24.0-dev.2"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"LOW"}],"references":["https://github.com/rustls/rustls/security/advisories/GHSA-w44r-93j7-qv28","https://github.com/rustls/rustls/pull/3355","https://github.com/rustls/rustls/commit/8fa0dc5d517a63411ad1e528249bdf5b098ae5e4","https://github.com/rustls/rustls/commit/f04804fa13341a9b1dc02b5d1dd8a746f2c4b7fb","https://github.com/rustls/rustls","https://github.com/rustls/rustls/releases/tag/v/0.23.46","https://rustsec.org/advisories/RUSTSEC-2026-0349.html"],"sourceUrl":"https://github.com/advisories/GHSA-w44r-93j7-qv28","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-w44r-93j7-qv28","identifiers":["GHSA-w44r-93j7-qv28","RUSTSEC-2026-0349"]},"retained":false,"historicalAffected":[]},{"revision":"e3b84c999d684daeb7ffba844aa9a69d","observedAt":"2026-10-24T13:19:54.901+00:00","statement":{"source":"osv","id":"RUSTSEC-2026-0349","aliases":["GHSA-w44r-93j7-qv28"],"title":"Unauthenticated ServerHello can downgrade later connections to classical key exchange","description":"The client recorded the server-selected key exchange group for each server\nname when processing the ServerHello, before the server was authenticated.\nThis record is used to predict which key share to send in future ClientHellos\nto that server name.\n\nA network attacker can answer one connection attempt with a ServerHello\nselecting X25519, and then close the connection. Later ClientHellos for that\nname carry only an X25519 key share, while `supported_groups` still lists\nX25519MLKEM768 first. If the genuine server accepts that share rather than\nsending a HelloRetryRequest for its preferred hybrid group, the handshake\ncompletes with classical-only key exchange and no error. This persists for as\nlong as the entry stays in the client's session store.\n\nThe impact is loss of post-quantum confidentiality for affected connections\n(\"harvest now, decrypt later\"). There is no key compromise and no\nauthentication bypass.\n\nThe following are not affected:\n\n- connections to servers which send a HelloRetryRequest for their preferred group,\n- clients with resumption disabled (as nothing is stored), and\n- other server names.\n\nThis behaviour is discussed in\n[draft-ietf-tls-key-share-prediction](https://www.ietf.org/archive/id/draft-ietf-tls-key-share-prediction-01.html#name-security-considerations),\nso the practical impact depends largely on server policy.","state":0,"publishedAt":"2026-10-14T12:00:00+00:00","modifiedAt":"2026-10-14T13:30:02.4757051+00:00","affected":[{"ecosystem":"crates.io","name":"rustls","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0.0.0-0"},{"kind":"fixed","version":"0.23.46"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","score":null,"severity":null}],"references":["https://crates.io/crates/rustls","https://rustsec.org/advisories/RUSTSEC-2026-0349.html","https://github.com/rustls/rustls/pull/3355"],"sourceUrl":"https://osv.dev/vulnerability/RUSTSEC-2026-0349","license":"OSV · upstream source license applies","key":"osv:RUSTSEC-2026-0349","identifiers":["RUSTSEC-2026-0349","GHSA-w44r-93j7-qv28"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-30T14:45:26.6987549+00:00","complete":true,"records":1764,"lastAttemptAt":"2026-10-30T14:45:26.6987549+00:00","lastSuccessAt":"2026-10-30T14:45:26.9497648+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:26.9497653+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-7e2c4e7288f2c464ad8c61f3bb6017374714faedcc781283ac06a706ee1a820b-9ae73af7991357f8171c14345365990a8a2ca2ac30d2f5c0345295ca47cd8b59","complete":true,"records":417062,"lastAttemptAt":"2026-10-30T14:45:26.2761545+00:00","lastSuccessAt":"2026-10-30T13:45:42.363036+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:26.2761545+00:00","snapshotPublishedAt":"2026-10-30T13:19:40+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-2061c7564831481480eca7336a6a2d59","complete":false,"records":13525,"lastAttemptAt":"2026-10-30T14:57:22.1548673+00:00","lastSuccessAt":"2026-10-30T14:57:22.151+00:00","error":"74 identifier lookups failed; latest failures include HTTP 403. Other identifiers were checked independently.","lastVerifiedAt":"2026-10-30T14:57:22.151+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":12100,"expectedIdentifiers":13603,"failedIdentifiers":74},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-30T14:45:26.6987549+00:00","complete":true,"records":1094,"lastAttemptAt":"2026-10-30T14:45:26.6987549+00:00","lastSuccessAt":"2026-10-30T14:45:26.9516817+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:26.951682+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-6a13c6f8f39a448a8b96c895e97b0fc8","complete":true,"records":13543,"lastAttemptAt":"2026-10-30T14:45:34.6994115+00:00","lastSuccessAt":"2026-10-30T14:45:34.696+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:34.696+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13603,"expectedIdentifiers":13603,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-b597efeb8fc540d31a792e2148f8b153f027cb0902f6eec1f988f717bba80dd6","complete":true,"records":9806,"lastAttemptAt":"2026-10-30T14:45:26.6211704+00:00","lastSuccessAt":"2026-10-30T11:49:32.1566+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:26.6211704+00:00","snapshotPublishedAt":"2026-10-30T11:03:04+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-2de9ccc5290f060c7aa63f89c25dd76f655a64ba1aba7c05c97fa3bee4f09899","complete":true,"records":1967,"lastAttemptAt":"2026-10-30T14:45:26.3367706+00:00","lastSuccessAt":"2026-10-28T20:55:34.2982937+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:26.3367706+00:00","snapshotPublishedAt":"2026-10-28T20:03:08+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-f63fa91e750071ae88c9f82019ecd6c982fa4fcc1d3dc5ceb5d9c642fb6bf05c","complete":true,"records":3023,"lastAttemptAt":"2026-10-30T14:45:26.6363468+00:00","lastSuccessAt":"2026-10-30T11:49:36.4759887+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:26.6363468+00:00","snapshotPublishedAt":"2026-10-30T11:18:14+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-38769c8a86ea1c9a6224e5523e119bd23337098bd8f535cc5952f8ec88cdd622","complete":true,"records":230950,"lastAttemptAt":"2026-10-30T14:45:26.5064351+00:00","lastSuccessAt":"2026-10-30T13:47:22.3495471+00:00","error":null,"lastVerifiedAt":"2026-10-30T14:45:26.5064351+00:00","snapshotPublishedAt":"2026-10-30T13:33:12+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}