{"id":"PYSEC-2026-3615","revision":null,"records":[{"revision":"6d30bfb7f3a64e35a2f1a752c763d32a","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-54609","aliases":[],"title":"QTINeon has unauthenticated relay-to-host amplification via unbounded RECONNECT_REQUEST forwarding","description":"QTI Neon is a minimal, game-agnostic, relay-based UDP multiplayer protocol library. In version 1.0.0, the relay's handleReconnectRequest forwards RECONNECT_REQUEST packets to the host without bounding them, so an unauthenticated client can drive relay-to-host amplification and cause a denial of service on the host. No fixed version is available as of this review.","state":0,"publishedAt":"2026-07-28T16:36:37.938+00:00","modifiedAt":"2026-07-28T17:07:15.08+00:00","affected":[{"ecosystem":"Vendor product","name":"QTINeon","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"Quiet-Terminal-Interactive\",\n                    \"product\": \"QTINeon\",\n                    \"versions\": [\n                        {\n                            \"version\": \"1.0.0\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H","score":8.6,"severity":"HIGH"}],"references":["https://github.com/Quiet-Terminal-Interactive/QTINeon/security/advisories/GHSA-85rg-p3fr-xc2f"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-54609","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-54609","identifiers":["CVE-2026-54609"]},"retained":false,"historicalAffected":[]},{"revision":"cdd1df581f8643b1a93b2c0403c0e9b1","observedAt":"2026-10-25T13:17:28.253+00:00","statement":{"source":"nvd","id":"CVE-2026-54609","aliases":[],"title":"QTI Neon is a minimal, game-agnostic, relay-based UDP multiplayer protocol library. In version 1.0.0, the relay's handleReconnectRequest forwards RECONNECT_REQUEST packets to the host without bounding them, so an unauthenticated client can …","description":"QTI Neon is a minimal, game-agnostic, relay-based UDP multiplayer protocol library. In version 1.0.0, the relay's handleReconnectRequest forwards RECONNECT_REQUEST packets to the host without bounding them, so an unauthenticated client can drive relay-to-host amplification and cause a denial of service on the host. No fixed version is available as of this review.","state":0,"publishedAt":"2026-07-28T17:16:52.507+00:00","modifiedAt":"2026-10-23T23:10:00.157+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H","score":8.6,"severity":"HIGH"}],"references":["https://github.com/Quiet-Terminal-Interactive/QTINeon/security/advisories/GHSA-85rg-p3fr-xc2f"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-54609","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-400","CWE-406","CWE-770"],"productCriteria":[],"sourceDates":{"published":"2026-07-28T17:16:52.507","lastModified":"2026-10-23T23:10:00.157"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-54609","identifiers":["CVE-2026-54609"]},"retained":false,"historicalAffected":[]},{"revision":"4dcdea27568e4982b72f7c078dbf68e1","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-85rg-p3fr-xc2f","aliases":["CVE-2026-54609","PYSEC-2026-3615"],"title":"QTINeon has unauthenticated relay-to-host amplification via unbounded RECONNECT_REQUEST forwarding","description":"### Impact\nThe relay's reconnect handler forwards every `RECONNECT_REQUEST` to the host without deduplication or a size cap on the `pendingReconnects` map, unlike the connect flow which guards against this with `maxPendingConnections`. An unauthenticated attacker who knows a valid session ID can send `RECONNECT_REQUEST` packets from many spoofed source addresses; each packet that passes the session lookup is forwarded to the host as a new reconnect attempt. Because the per-source rate limiter assigns a fresh token bucket to each spoofed IP, it provides no protection. The host receives one forwarded packet per spoofed source per cleanup cycle, making the relay an amplification vector for denial-of-service against the host. The host's real address is never exposed to clients by design, so this is the primary viable DoS path against it. A secondary issue: once more than `maxRateLimiters` spoofed IPs are seen, `performCleanup` calls `rateLimiters.clear()`, resetting rate limit state for all sources including legitimate ones.\n\nAffected: `NeonRelay` in all three implementations (Java, Python, TypeScript).\n\n### Patches\nNot yet patched. Fix consists of three changes to handleReconnectRequest in each implementation:\n\n1. Reject the request if `pendingReconnects.size() >= maxPendingConnections` (mirrors the existing connect-flow guard)\n2. Only forward to the host if the `sessionId:clientId` key is not already present in `pendingReconnects` — the map entry can still be updated with the new source address, but the host only needs to validate once per slot\n3. In `performCleanup`, evict throttled entries before falling back to `rateLimiters.clear()` to avoid resetting legitimate sources' rate limit state\n\n### Workarounds\nOperators can partially mitigate by placing the relay behind a network-level filter that drops packets with spoofed source addresses (BCP38/uRPF). This does not address the missing `pendingReconnects` size cap or the `rateLimiters.clear()` issue but eliminates the amplification path in most deployment environments.\n\n### References\n- PROTOCOL.md — reconnect flow\n- ARCHITECTURE.md — reconnect handshake detail (step 4 describes the unbounded `put`)","state":0,"publishedAt":"2026-07-28T16:36:47+00:00","modifiedAt":"2026-08-04T14:40:38.5190293+00:00","affected":[{"ecosystem":"Maven","name":"com.quietterminal:qti-neon","ranges":[],"versions":["1.0.0"],"rawVersionEvidence":null},{"ecosystem":"PyPI","name":"qti-neon","ranges":[],"versions":["1.0.0"],"rawVersionEvidence":null},{"ecosystem":"npm","name":"qti-neon","ranges":[],"versions":["1.0.0"],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/Quiet-Terminal-Interactive/QTINeon/security/advisories/GHSA-85rg-p3fr-xc2f","https://github.com/Quiet-Terminal-Interactive/QTINeon"],"sourceUrl":"https://github.com/advisories/GHSA-85rg-p3fr-xc2f","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-85rg-p3fr-xc2f","identifiers":["GHSA-85rg-p3fr-xc2f","CVE-2026-54609","PYSEC-2026-3615"]},"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-26T11:36:23.2920201+00:00","complete":true,"records":1756,"lastAttemptAt":"2026-10-26T11:36:23.2920201+00:00","lastSuccessAt":"2026-10-26T11:36:23.5142731+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:23.5142748+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-5ba1945314e042c2ced14b33f3680fa71692812d925544312b218f5eb8a26e71-e7962156c388e029d9e5dbbcda79fbd40ade61bdd41d51546adb4696b3e29228","complete":true,"records":414161,"lastAttemptAt":"2026-10-26T11:36:10.3293998+00:00","lastSuccessAt":"2026-10-26T11:36:10.2537359+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:10.3293998+00:00","snapshotPublishedAt":"2026-10-26T11:28:55+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":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-43321610382942b8ad8c85917eab1546","complete":false,"records":4735,"lastAttemptAt":"2026-10-26T11:36:27.570174+00:00","lastSuccessAt":"2026-10-24T23:18:49.862+00:00","error":"InvalidDataException","lastVerifiedAt":"2026-10-24T23:18:49.862+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":4764,"expectedIdentifiers":13477},{"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-26T11:36:23.2920201+00:00","complete":true,"records":1093,"lastAttemptAt":"2026-10-26T11:36:23.2920201+00:00","lastSuccessAt":"2026-10-26T11:36:23.6271598+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:23.6271612+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":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-114096430e32489f93a3ae96f397b2db","complete":true,"records":13416,"lastAttemptAt":"2026-10-26T11:36:25.3338531+00:00","lastSuccessAt":"2026-10-26T11:36:25.326+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:25.326+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13477,"expectedIdentifiers":13477},{"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-2375a4e597279abf92e8747e140fe8da9d421877cd49cae3ac69a2cb78469b2c","complete":true,"records":9779,"lastAttemptAt":"2026-10-26T11:36:10.7420905+00:00","lastSuccessAt":"2026-10-24T13:19:53.1346702+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:10.7420905+00:00","snapshotPublishedAt":"2026-10-24T03:03:12+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-16ad89dfea13ab9e9b0108e63a759d63bd4559cc68b58491107d62ee35bbbaf2","complete":true,"records":1965,"lastAttemptAt":"2026-10-26T11:36:10.517478+00:00","lastSuccessAt":"2026-10-23T16:01:26.4487605+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:10.517478+00:00","snapshotPublishedAt":"2026-10-21T12:18:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":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-7d18ad8657bc2f95d55948e9e16b3c82a8ac06830df5ec8d356048b8420b72c3","complete":true,"records":2972,"lastAttemptAt":"2026-10-26T11:36:23.2053293+00:00","lastSuccessAt":"2026-10-26T11:36:23.0131888+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:23.2053293+00:00","snapshotPublishedAt":"2026-10-26T11:33:16+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":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-654e90fb44abcd729ddecf56d54c1b46ce87ca3181850e8bc65d5c8befceb659","complete":true,"records":230805,"lastAttemptAt":"2026-10-26T11:36:10.6367182+00:00","lastSuccessAt":"2026-10-26T08:22:30.1390577+00:00","error":null,"lastVerifiedAt":"2026-10-26T11:36:10.6367182+00:00","snapshotPublishedAt":"2026-10-26T07:48:28+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null}]}