CVE-2024-58265
Description
The snow crate before 0.9.5 for Rust, when stateful TransportState is used, allows incrementing a nonce and thereby denying message delivery.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Unauthenticated nonce increment in snow's stateful TransportState can lead to denial of service by preventing message delivery.
Vulnerability
Description
The snow crate, a Rust implementation of the Noise Protocol Framework, contains a logic bug in versions prior to 0.9.5. When using the stateful TransportState, unauthenticated payloads can cause the internal nonce counter to increment, breaking the expected sequence of nonces [1]. This bug stems from the read_message function not properly validating the authenticity of incoming data before incrementing the nonce [4].
Exploitation
An attacker with the ability to inject packets into the communication channel (e.g., man-in-the-middle position) can send arbitrary garbage data to the receiving party. Since the nonce is incremented on receipt without authentication, the receiver's state becomes desynchronized from the sender [4]. No prior authentication or special privileges are required beyond network access to the channel [2].
Impact
Successful exploitation results in a denial of service (DoS) where legitimate messages from the sender are rejected because the receiver's nonce does not match. This prevents any further message delivery over the affected Noise session [1][4]. The vulnerability is classified under crypto-failure and DoS categories [4].
Mitigation
The issue has been patched in snow version 0.9.5. Users are strongly recommended to update to this version or later [2][4]. Those using StatelessTransportState are not affected [4]. No workarounds are mentioned in the advisory.
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
snowcrates.io | < 0.9.5 | 0.9.5 |
Affected products
1- mcginty/snowv5Range: 0
Patches
112e8ae55547aStateful nonce desync fix
3 files changed · +54 −14
src/cipherstate.rs+2 −2 modified@@ -59,12 +59,12 @@ impl CipherState { } validate_nonce(self.n)?; - let len = self.cipher.decrypt(self.n, authtext, ciphertext, out); + let len = self.cipher.decrypt(self.n, authtext, ciphertext, out)?; // We have validated this will not wrap around. self.n += 1; - len + Ok(len) } pub fn encrypt(&mut self, plaintext: &[u8], out: &mut [u8]) -> Result<usize, Error> {
src/resolvers/default.rs+2 −5 modified@@ -1,10 +1,7 @@ use blake2::{Blake2b, Blake2b512, Blake2s, Blake2s256}; #[cfg(feature = "xchachapoly")] use chacha20poly1305::XChaCha20Poly1305; -use chacha20poly1305::{ - aead::AeadInPlace, - KeyInit, ChaCha20Poly1305, -}; +use chacha20poly1305::{aead::AeadInPlace, ChaCha20Poly1305, KeyInit}; use curve25519_dalek::montgomery::MontgomeryPoint; #[cfg(feature = "pqclean_kyber1024")] use pqcrypto_kyber::kyber1024; @@ -611,7 +608,7 @@ mod tests { keypair.dh(&public, &mut output).unwrap(); assert_eq!( hex::encode(output), - "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552" + "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552" ); }
tests/general.rs+50 −7 modified@@ -417,6 +417,7 @@ fn test_rekey() { h_i.rekey_outgoing(); let len = h_i.write_message(b"hack the planet", &mut buffer_msg).unwrap(); assert!(h_r.read_message(&buffer_msg[..len], &mut buffer_out).is_err()); + h_r.set_receiving_nonce(h_i.sending_nonce()); // rekey incoming on responder h_r.rekey_incoming(); @@ -428,6 +429,7 @@ fn test_rekey() { h_r.rekey_outgoing(); let len = h_r.write_message(b"hack the planet", &mut buffer_msg).unwrap(); assert!(h_i.read_message(&buffer_msg[..len], &mut buffer_out).is_err()); + h_i.set_receiving_nonce(h_r.sending_nonce()); // rekey incoming on initiator h_i.rekey_incoming(); @@ -444,37 +446,45 @@ fn test_rekey_manually() { let mut buffer_msg = [0u8; 200]; let mut buffer_out = [0u8; 200]; + + // Do a handshake, and transition to stateful transport mode. let len = h_i.write_message(b"abc", &mut buffer_msg).unwrap(); h_r.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); - let len = h_r.write_message(b"defg", &mut buffer_msg).unwrap(); h_i.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); - let mut h_i = h_i.into_transport_mode().unwrap(); let mut h_r = h_r.into_transport_mode().unwrap(); - // test message initiator->responder before rekeying initiator + // test sanity message initiator->responder before rekeying initiator let len = h_i.write_message(b"hack the planet", &mut buffer_msg).unwrap(); let len = h_r.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); assert_eq!(&buffer_out[..len], b"hack the planet"); - // rekey initiator (on initiator) + // rekey initiator-side initiator key to K1 without rekeying the responder, + // expecting a decryption failure. + // + // The message *should* have failed to read, so we also force nonce re-sync. h_i.rekey_manually(Some(&[1u8; 32]), None); let len = h_i.write_message(b"hack the planet", &mut buffer_msg).unwrap(); assert!(h_r.read_message(&buffer_msg[..len], &mut buffer_out).is_err()); + h_r.set_receiving_nonce(h_i.sending_nonce()); - // rekey initiator (on responder) + // rekey responder-side responder key to K1, expecting a successful decryption. h_r.rekey_manually(Some(&[1u8; 32]), None); let len = h_i.write_message(b"hack the planet", &mut buffer_msg).unwrap(); let len = h_r.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); assert_eq!(&buffer_out[..len], b"hack the planet"); - // rekey responder (on responder) + // rekey responder-side responder key to K1 without rekeying the initiator, + // expecting a decryption failure. + // + // The message *should* have failed to read, so we also force nonce re-sync. h_r.rekey_manually(None, Some(&[1u8; 32])); let len = h_r.write_message(b"hack the planet", &mut buffer_msg).unwrap(); assert!(h_i.read_message(&buffer_msg[..len], &mut buffer_out).is_err()); + h_i.set_receiving_nonce(h_r.sending_nonce()); - // rekey responder (on initiator) + // rekey intiator-side responder key to K1, expecting a successful decryption. h_i.rekey_manually(None, Some(&[1u8; 32])); let len = h_r.write_message(b"hack the planet", &mut buffer_msg).unwrap(); let len = h_i.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); @@ -870,3 +880,36 @@ fn test_stateless_nonce_maximum_behavior() { Err(snow::Error::State(snow::error::StateProblem::Exhausted)) )); } + +#[test] +fn test_stateful_nonce_increment_behavior() { + let params: NoiseParams = "Noise_NN_25519_ChaChaPoly_SHA256".parse().unwrap(); + let mut h_i = Builder::new(params.clone()).build_initiator().unwrap(); + let mut h_r = Builder::new(params).build_responder().unwrap(); + + let mut buffer_msg = [0u8; 200]; + let mut buffer_out = [0u8; 200]; + let len = h_i.write_message(b"abc", &mut buffer_msg).unwrap(); + h_r.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); + + let len = h_r.write_message(b"defg", &mut buffer_msg).unwrap(); + h_i.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); + + let mut h_i = h_i.into_transport_mode().unwrap(); + let mut h_r = h_r.into_transport_mode().unwrap(); + + let len = h_i.write_message(b"xyz", &mut buffer_msg).unwrap(); + + // Corrupt the message by incrementing a byte in the payload + let mut corrupted = buffer_msg[..len].to_owned(); + corrupted[0] = corrupted[0].wrapping_add(1); + + // This should result in an error, but should not change any internal state + assert!(h_r.read_message(&corrupted, &mut buffer_out).is_err()); + + // This should now succeed as the nonce counter should have remained the same + h_r.read_message(&buffer_msg[..len], &mut buffer_out).unwrap(); + + // This should now fail again as the nonce counter should have incremented + assert!(h_r.read_message(&buffer_msg[..len], &mut buffer_out).is_err()); +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-7g9j-g5jg-3vv3ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-58265ghsaADVISORY
- github.com/mcginty/snow/commit/12e8ae55547ae297d5f70599e5c884ea891303ebghsaWEB
- github.com/mcginty/snow/security/advisories/GHSA-7g9j-g5jg-3vv3ghsaWEB
- rustsec.org/advisories/RUSTSEC-2024-0011.htmlghsaWEB
- crates.io/crates/snowmitre
News mentions
0No linked articles in our index yet.