CVE-2025-53359
Description
ethereum is a common ethereum structs for Rust. Prior to ethereum crate v0.18.0, signature malleability (according to EIP-2) was only checked for "legacy" transactions, but not for EIP-2930, EIP-1559 and EIP-7702 transactions. This is a specification deviation. The signature malleability itself is not a security issue and not as high of a risk if the ethereum crate is used on a single-implementation blockchain. This issue has been patched in version v0.18.0. A workaround for this issue involves manually checking transaction malleability outside of the crate, however upgrading is recommended.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
ethereumcrates.io | < 0.18.0 | 0.18.0 |
Affected products
1- Range: v0.16.0, v0.17.0
Patches
223e082f0df5a2dd9d1d5d093Always maintain the invariant for TransactionSignature (#67)
6 files changed · +275 −114
src/block.rs+14 −10 modified@@ -126,10 +126,16 @@ impl From<BlockV1> for BlockV3 { mod tests { use super::*; use crate::transaction::{ - AuthorizationListItem, EIP7702Transaction, TransactionAction, TransactionV3, + eip2930, eip7702::AuthorizationListItem, legacy::TransactionAction, EIP7702Transaction, + TransactionV3, }; use ethereum_types::{H160, H256, U256}; + const ONE: H256 = H256([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, + ]); + #[test] fn block_v3_with_eip7702_transaction() { // Create an EIP-7702 transaction @@ -147,13 +153,13 @@ mod tests { chain_id: 1, address: H160::zero(), nonce: U256::zero(), - y_parity: false, - r: H256::zero(), - s: H256::zero(), + signature: eip2930::MalleableTransactionSignature { + odd_y_parity: false, + r: ONE, + s: ONE, + }, }], - odd_y_parity: false, - r: H256::zero(), - s: H256::zero(), + signature: eip2930::TransactionSignature::new(false, ONE, ONE).unwrap(), }); // Create a block with the EIP-7702 transaction @@ -207,9 +213,7 @@ mod tests { value: U256::zero(), input: vec![], access_list: vec![], - odd_y_parity: false, - r: H256::zero(), - s: H256::zero(), + signature: eip2930::TransactionSignature::new(false, ONE, ONE).unwrap(), }); let partial_header = PartialHeader {
src/transaction/eip1559.rs+14 −13 modified@@ -2,10 +2,9 @@ use ethereum_types::{H256, U256}; use rlp::{DecoderError, Rlp, RlpStream}; use sha3::{Digest, Keccak256}; -use crate::{ - transaction::{AccessList, TransactionAction}, - Bytes, -}; +use crate::Bytes; + +pub use super::eip2930::{AccessList, TransactionAction, TransactionSignature}; #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr( @@ -28,9 +27,7 @@ pub struct EIP1559Transaction { pub value: U256, pub input: Bytes, pub access_list: AccessList, - pub odd_y_parity: bool, - pub r: H256, - pub s: H256, + pub signature: TransactionSignature, } impl EIP1559Transaction { @@ -69,9 +66,9 @@ impl rlp::Encodable for EIP1559Transaction { s.append(&self.value); s.append(&self.input); s.append_list(&self.access_list); - s.append(&self.odd_y_parity); - s.append(&U256::from_big_endian(&self.r[..])); - s.append(&U256::from_big_endian(&self.s[..])); + s.append(&self.signature.odd_y_parity()); + s.append(&U256::from_big_endian(&self.signature.r()[..])); + s.append(&U256::from_big_endian(&self.signature.s()[..])); } } @@ -91,9 +88,13 @@ impl rlp::Decodable for EIP1559Transaction { value: rlp.val_at(6)?, input: rlp.val_at(7)?, access_list: rlp.list_at(8)?, - odd_y_parity: rlp.val_at(9)?, - r: H256::from(rlp.val_at::<U256>(10)?.to_big_endian()), - s: H256::from(rlp.val_at::<U256>(11)?.to_big_endian()), + signature: { + let odd_y_parity = rlp.val_at(9)?; + let r = H256::from(rlp.val_at::<U256>(10)?.to_big_endian()); + let s = H256::from(rlp.val_at::<U256>(11)?.to_big_endian()); + TransactionSignature::new(odd_y_parity, r, s) + .ok_or(DecoderError::Custom("Invalid transaction signature format"))? + }, }) } }
src/transaction/eip2930.rs+122 −10 modified@@ -4,7 +4,117 @@ use ethereum_types::{Address, H256, U256}; use rlp::{DecoderError, Rlp, RlpStream}; use sha3::{Digest, Keccak256}; -use crate::{transaction::TransactionAction, Bytes}; +use crate::Bytes; + +pub use super::legacy::TransactionAction; + +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr( + feature = "with-scale", + derive( + scale_info::TypeInfo, + scale_codec::Encode, + scale_codec::Decode, + scale_codec::DecodeWithMemTracking + ) +)] +#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MalleableTransactionSignature { + pub odd_y_parity: bool, + pub r: H256, + pub s: H256, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr( + feature = "with-scale", + derive( + scale_info::TypeInfo, + scale_codec::Encode, + scale_codec::DecodeWithMemTracking + ) +)] +#[cfg_attr(feature = "with-serde", derive(serde::Serialize))] +pub struct TransactionSignature { + odd_y_parity: bool, + r: H256, + s: H256, +} + +impl TransactionSignature { + #[must_use] + pub fn new(odd_y_parity: bool, r: H256, s: H256) -> Option<Self> { + const LOWER: H256 = H256([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + ]); + const UPPER: H256 = H256([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, + 0xd0, 0x36, 0x41, 0x41, + ]); + + let is_valid = r < UPPER && r >= LOWER && s < UPPER && s >= LOWER; + + if is_valid { + Some(Self { odd_y_parity, r, s }) + } else { + None + } + } + + #[must_use] + pub fn odd_y_parity(&self) -> bool { + self.odd_y_parity + } + + #[must_use] + pub fn r(&self) -> &H256 { + &self.r + } + + #[must_use] + pub fn s(&self) -> &H256 { + &self.s + } + + #[must_use] + pub fn is_low_s(&self) -> bool { + const LOWER: H256 = H256([ + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x5d, 0x57, 0x6e, 0x73, 0x57, 0xa4, 0x50, 0x1d, 0xdf, 0xe9, 0x2f, 0x46, + 0x68, 0x1b, 0x20, 0xa0, + ]); + + self.s <= LOWER + } +} + +#[cfg(feature = "with-scale")] +impl scale_codec::Decode for TransactionSignature { + fn decode<I: scale_codec::Input>(value: &mut I) -> Result<Self, scale_codec::Error> { + let unchecked = MalleableTransactionSignature::decode(value)?; + match Self::new(unchecked.odd_y_parity, unchecked.r, unchecked.s) { + Some(signature) => Ok(signature), + None => Err(scale_codec::Error::from("Invalid signature")), + } + } +} + +#[cfg(feature = "with-serde")] +impl<'de> serde::Deserialize<'de> for TransactionSignature { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::de::Deserializer<'de>, + { + let unchecked = MalleableTransactionSignature::deserialize(deserializer)?; + Ok( + TransactionSignature::new(unchecked.odd_y_parity, unchecked.r, unchecked.s) + .ok_or(serde::de::Error::custom("invalid signature"))?, + ) + } +} #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr( @@ -61,9 +171,7 @@ pub struct EIP2930Transaction { pub value: U256, pub input: Bytes, pub access_list: AccessList, - pub odd_y_parity: bool, - pub r: H256, - pub s: H256, + pub signature: TransactionSignature, } impl EIP2930Transaction { @@ -100,9 +208,9 @@ impl rlp::Encodable for EIP2930Transaction { s.append(&self.value); s.append(&self.input); s.append_list(&self.access_list); - s.append(&self.odd_y_parity); - s.append(&U256::from_big_endian(&self.r[..])); - s.append(&U256::from_big_endian(&self.s[..])); + s.append(&self.signature.odd_y_parity()); + s.append(&U256::from_big_endian(&self.signature.r()[..])); + s.append(&U256::from_big_endian(&self.signature.s()[..])); } } @@ -121,9 +229,13 @@ impl rlp::Decodable for EIP2930Transaction { value: rlp.val_at(5)?, input: rlp.val_at(6)?, access_list: rlp.list_at(7)?, - odd_y_parity: rlp.val_at(8)?, - r: H256::from(rlp.val_at::<U256>(9)?.to_big_endian()), - s: H256::from(rlp.val_at::<U256>(10)?.to_big_endian()), + signature: { + let odd_y_parity = rlp.val_at(8)?; + let r = H256::from(rlp.val_at::<U256>(9)?.to_big_endian()); + let s = H256::from(rlp.val_at::<U256>(10)?.to_big_endian()); + TransactionSignature::new(odd_y_parity, r, s) + .ok_or(DecoderError::Custom("Invalid transaction signature format"))? + }, }) } }
src/transaction/eip7702.rs+61 −52 modified@@ -5,9 +5,10 @@ use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; use rlp::{DecoderError, Rlp, RlpStream}; use sha3::{Digest, Keccak256}; -use crate::{ - transaction::{AccessList, TransactionAction}, - Bytes, +use crate::Bytes; + +pub use super::eip2930::{ + AccessList, MalleableTransactionSignature, TransactionAction, TransactionSignature, }; /// Error type for EIP-7702 authorization signature recovery @@ -45,9 +46,7 @@ pub struct AuthorizationListItem { pub chain_id: u64, pub address: Address, pub nonce: U256, - pub y_parity: bool, - pub r: H256, - pub s: H256, + pub signature: MalleableTransactionSignature, } impl rlp::Encodable for AuthorizationListItem { @@ -56,9 +55,9 @@ impl rlp::Encodable for AuthorizationListItem { s.append(&self.chain_id); s.append(&self.address); s.append(&self.nonce); - s.append(&self.y_parity); - s.append(&U256::from_big_endian(&self.r[..])); - s.append(&U256::from_big_endian(&self.s[..])); + s.append(&self.signature.odd_y_parity); + s.append(&U256::from_big_endian(&self.signature.r[..])); + s.append(&U256::from_big_endian(&self.signature.s[..])); } } @@ -72,29 +71,48 @@ impl rlp::Decodable for AuthorizationListItem { chain_id: rlp.val_at(0)?, address: rlp.val_at(1)?, nonce: rlp.val_at(2)?, - y_parity: rlp.val_at(3)?, - r: H256::from(rlp.val_at::<U256>(4)?.to_big_endian()), - s: H256::from(rlp.val_at::<U256>(5)?.to_big_endian()), + signature: { + let odd_y_parity = rlp.val_at(3)?; + let r = H256::from(rlp.val_at::<U256>(4)?.to_big_endian()); + let s = H256::from(rlp.val_at::<U256>(5)?.to_big_endian()); + MalleableTransactionSignature { odd_y_parity, r, s } + }, }) } } impl AuthorizationListItem { + /// Check and get the signature. + /// + /// This checks that the signature is not malleable, but does not otherwise check or recover + /// the public key. + pub fn signature(&self) -> Option<TransactionSignature> { + TransactionSignature::new( + self.signature.odd_y_parity, + self.signature.r, + self.signature.s, + ) + } + /// Recover the authorizing address from the authorization signature according to EIP-7702 pub fn authorizing_address(&self) -> Result<Address, AuthorizationError> { // Create the authorization message hash according to EIP-7702 let message_hash = self.authorization_message_hash(); + let sigv = self + .signature() + .ok_or(AuthorizationError::InvalidSignature)?; + // Create signature from r and s components let mut signature_bytes = [0u8; 64]; - signature_bytes[0..32].copy_from_slice(&self.r[..]); - signature_bytes[32..64].copy_from_slice(&self.s[..]); + signature_bytes[0..32].copy_from_slice(&sigv.r()[..]); + signature_bytes[32..64].copy_from_slice(&sigv.s()[..]); // Create the signature and recovery ID let signature = Signature::from_bytes(&signature_bytes.into()) .map_err(|_| AuthorizationError::InvalidSignature)?; - let recovery_id = RecoveryId::try_from(if self.y_parity { 1u8 } else { 0u8 }) + let recovery_id = RecoveryId::try_from(if sigv.odd_y_parity() { 1u8 } else { 0u8 }) .map_err(|_| AuthorizationError::InvalidRecoveryId)?; // Recover the verifying key using VerifyingKey::recover_from_prehash @@ -169,9 +187,7 @@ pub struct EIP7702Transaction { pub data: Bytes, pub access_list: AccessList, pub authorization_list: AuthorizationList, - pub odd_y_parity: bool, - pub r: H256, - pub s: H256, + pub signature: TransactionSignature, } impl EIP7702Transaction { @@ -212,9 +228,9 @@ impl rlp::Encodable for EIP7702Transaction { s.append(&self.data); s.append_list(&self.access_list); s.append_list(&self.authorization_list); - s.append(&self.odd_y_parity); - s.append(&U256::from_big_endian(&self.r[..])); - s.append(&U256::from_big_endian(&self.s[..])); + s.append(&self.signature.odd_y_parity()); + s.append(&U256::from_big_endian(&self.signature.r()[..])); + s.append(&U256::from_big_endian(&self.signature.s()[..])); } } @@ -235,9 +251,13 @@ impl rlp::Decodable for EIP7702Transaction { data: rlp.val_at(7)?, access_list: rlp.list_at(8)?, authorization_list: rlp.list_at(9)?, - odd_y_parity: rlp.val_at(10)?, - r: H256::from(rlp.val_at::<U256>(11)?.to_big_endian()), - s: H256::from(rlp.val_at::<U256>(12)?.to_big_endian()), + signature: { + let odd_y_parity = rlp.val_at(10)?; + let r = H256::from(rlp.val_at::<U256>(11)?.to_big_endian()); + let s = H256::from(rlp.val_at::<U256>(12)?.to_big_endian()); + TransactionSignature::new(odd_y_parity, r, s) + .ok_or(DecoderError::Custom("Invalid transaction signature format"))? + }, }) } } @@ -340,9 +360,11 @@ mod tests { chain_id, address, nonce, - y_parity, - r, - s, + signature: MalleableTransactionSignature { + odd_y_parity: y_parity, + r, + s, + }, }; // Recover the authorizing address @@ -371,34 +393,21 @@ mod tests { #[test] fn test_authorizing_address_error_handling() { // Test with invalid signature components (zero values are invalid in ECDSA) - let auth_item = AuthorizationListItem { - chain_id: 1, - address: Address::from_slice(&[0x42u8; 20]), - nonce: U256::zero(), - y_parity: false, - r: H256::zero(), // Invalid r value (r cannot be zero) - s: H256::zero(), // Invalid s value (s cannot be zero) - }; - - // This should return an error due to invalid signature - let result = auth_item.authorizing_address(); - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AuthorizationError::InvalidSignature); + assert!(TransactionSignature::new( + false, + H256::zero(), // Invalid r value (r cannot be zero) + H256::zero(), // Invalid s value (s cannot be zero) + ) + .is_none()); // Test with values that are too high (greater than secp256k1 curve order) // secp256k1 curve order is FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - let auth_item_high_values = AuthorizationListItem { - chain_id: 1, - address: Address::from_slice(&[0x42u8; 20]), - nonce: U256::zero(), - y_parity: false, + assert!(TransactionSignature::new( + false, // Use maximum possible values which exceed the curve order - r: H256::from_slice(&[0xFF; 32]), - s: H256::from_slice(&[0xFF; 32]), - }; - - let result = auth_item_high_values.authorizing_address(); - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AuthorizationError::InvalidSignature); + H256::from_slice(&[0xFF; 32]), + H256::from_slice(&[0xFF; 32]), + ) + .is_none()); } }
src/transaction/legacy.rs+24 −1 modified@@ -91,7 +91,7 @@ impl TransactionRecoveryId { feature = "with-scale", derive(scale_info::TypeInfo, scale_codec::DecodeWithMemTracking) )] -#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "with-serde", derive(serde::Serialize))] pub struct TransactionSignature { v: TransactionRecoveryId, r: H256, @@ -181,6 +181,29 @@ impl scale_codec::Decode for TransactionSignature { } } +#[cfg(feature = "with-serde")] +#[derive(serde::Deserialize)] +struct TransactionSignatureUnchecked { + v: u64, + r: H256, + s: H256, +} + +#[cfg(feature = "with-serde")] +impl<'de> serde::Deserialize<'de> for TransactionSignature { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::de::Deserializer<'de>, + { + let unchecked = TransactionSignatureUnchecked::deserialize(deserializer)?; + + Ok( + TransactionSignature::new(unchecked.v, unchecked.r, unchecked.s) + .ok_or(serde::de::Error::custom("invalid signature"))?, + ) + } +} + #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr( feature = "with-scale",
src/transaction/mod.rs+40 −28 modified@@ -1,23 +1,15 @@ -mod eip1559; -mod eip2930; -mod eip7702; -mod legacy; +pub mod eip1559; +pub mod eip2930; +pub mod eip7702; +pub mod legacy; use bytes::BytesMut; use ethereum_types::H256; use rlp::{DecoderError, Rlp}; pub use self::{ - eip1559::{EIP1559Transaction, EIP1559TransactionMessage}, - eip2930::{AccessList, AccessListItem, EIP2930Transaction, EIP2930TransactionMessage}, - eip7702::{ - AuthorizationList, AuthorizationListItem, EIP7702Transaction, EIP7702TransactionMessage, - AUTHORIZATION_MAGIC, SET_CODE_TX_TYPE, - }, - legacy::{ - LegacyTransaction, LegacyTransactionMessage, TransactionAction, TransactionRecoveryId, - TransactionSignature, - }, + eip1559::EIP1559Transaction, eip2930::EIP2930Transaction, eip7702::EIP7702Transaction, + legacy::LegacyTransaction, }; use crate::enveloped::{EnvelopedDecodable, EnvelopedDecoderError, EnvelopedEncodable}; @@ -328,7 +320,14 @@ pub type TransactionAny = TransactionV3; #[cfg(test)] mod tests { - use super::*; + use super::{ + eip2930::{self, AccessListItem}, + eip7702::AuthorizationListItem, + legacy::{self, TransactionAction}, + EIP1559Transaction, EIP2930Transaction, EIP7702Transaction, EnvelopedDecodable, + TransactionV0, TransactionV1, TransactionV2, TransactionV3, + }; + use crate::enveloped::*; use ethereum_types::U256; use hex_literal::hex; @@ -353,7 +352,7 @@ mod tests { ), value: U256::from(10) * 1_000_000_000 * 1_000_000_000, input: hex!("a9059cbb000000000213ed0f886efd100b67c7e4ec0a85a7d20dc971600000000000000000000015af1d78b58c4000").into(), - signature: TransactionSignature::new(38, hex!("be67e0a07db67da8d446f76add590e54b6e92cb6b8f9835aeb67540579a27717").into(), hex!("2d690516512020171c1ec870f6ff45398cc8609250326be89915fb538e7bd718").into()).unwrap(), + signature: legacy::TransactionSignature::new(38, hex!("be67e0a07db67da8d446f76add590e54b6e92cb6b8f9835aeb67540579a27717").into(), hex!("2d690516512020171c1ec870f6ff45398cc8609250326be89915fb538e7bd718").into()).unwrap(), }; assert_eq!( @@ -389,9 +388,12 @@ mod tests { storage_keys: vec![], }, ], - odd_y_parity: false, - r: hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0").into(), - s: hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094").into(), + signature: eip2930::TransactionSignature::new( + false, + hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0").into(), + hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094").into(), + ) + .unwrap(), }); assert_eq!( @@ -428,9 +430,12 @@ mod tests { storage_keys: vec![], }, ], - odd_y_parity: false, - r: hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0").into(), - s: hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094").into(), + signature: eip2930::TransactionSignature::new( + false, + hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0").into(), + hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094").into(), + ) + .unwrap(), }); assert_eq!( @@ -463,13 +468,20 @@ mod tests { chain_id: 5, address: hex!("de0b295669a9fd93d5f28d9ec85e40f4cb697bae").into(), nonce: 1.into(), - y_parity: false, - r: hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0").into(), - s: hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094").into(), + signature: eip2930::MalleableTransactionSignature { + odd_y_parity: false, + r: hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0") + .into(), + s: hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094") + .into(), + }, }], - odd_y_parity: false, - r: hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0").into(), - s: hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094").into(), + signature: eip2930::TransactionSignature::new( + false, + hex!("36b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc0903590c16b02b0").into(), + hex!("5edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094").into(), + ) + .unwrap(), }); assert_eq!(
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-3w94-vq2x-v5wrghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-53359ghsaADVISORY
- github.com/rust-ethereum/ethereum/commit/2dd9d1d5d0936ec7350093ff3a5a7169a349db77nvdWEB
- github.com/rust-ethereum/ethereum/pull/67nvdWEB
- github.com/rust-ethereum/ethereum/security/advisories/GHSA-3w94-vq2x-v5wrnvdWEB
News mentions
0No linked articles in our index yet.