nimiq-keys: Denial of service in Ed25519 multisig delinearization via invalid curve points
Description
Impact
A denial-of-service vulnerability exists in the Ed25519 multisig delinearization code path. Ed25519PublicKey::delinearize() in keys/src/multisig/mod.rs called .unwrap() on curve point decompression, which panics when a public key is constructed from 32 bytes that do not represent a valid point on the Ed25519 curve. Ed25519PublicKey construction only validates byte length, not curve membership, so invalid keys can reach the delinearization path and crash the hosting process.
A secondary panic existed in Commitment::From<[u8; 32]>, which similarly called .unwrap() on a failing curve point decompression.
Who is affected: Browser and desktop wallet users of the web-client WASM library and the nimiq-wallet crate, when initiating a multisig operation with an attacker-supplied public key. An attacker must convince the user to include a crafted public key in a multisig setup — this is not a remotely triggerable node/validator crash.
Who is NOT affected: Validator nodes, consensus, blockchain, mempool, and networking code. There is no on-chain multisig account type; multisig is a purely client-side construct, and no validator/consensus code calls the multisig delinearization path.
Patches
See PR.
Workarounds
No code-level workaround exists short of the patch. Users of wallet applications can mitigate exposure by only performing multisig operations with public keys received from trusted sources.
### Resources - Affected code: keys/src/multisig/mod.rs, keys/src/multisig/commitment.rs
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A denial-of-service vulnerability in Nimiq's Ed25519 multisig delinearization allows an attacker to crash wallet applications by supplying an invalid curve point as a public key.
Root
Cause
The vulnerability resides in the Ed25519 multisig delinearization code path. Ed25519PublicKey::delinearize() in keys/src/multisig/mod.rs calls .unwrap() on curve point decompression, which panics when a public key is constructed from 32 bytes that do not represent a valid point on the Ed25519 curve [1][3]. A secondary panic exists in Commitment::From<[u8; 32]>, which similarly calls .unwrap() on a failing decompression [3]. The Ed25519PublicKey constructor only validates byte length, not curve membership, so invalid keys can reach the delinearization path and crash the hosting process [1][3].
Exploitation
An attacker must convince a user to include a crafted public key in a multisig setup — this is not a remotely triggerable node/validator crash [3]. The attack surface is limited to browser and desktop wallet users of the web-client WASM library and the nimiq-wallet crate when initiating a multisig operation with an attacker-supplied public key [3]. Validator nodes, consensus, blockchain, mempool, and networking code are not affected because multisig is a purely client-side construct and no validator/consensus code calls the multisig delinearization path [3].
Impact
Successful exploitation results in a denial of service: the wallet application panics and crashes, preventing the user from completing the multisig operation [1][3]. There is no on-chain multisig account type, so the blockchain itself is not impacted [3].
Mitigation
The issue is patched in commit 3bc449a8138960c4de6bfd506bad1730c621d4de, which replaces .unwrap() calls with proper error handling [1]. The fix is included in release v1.4.0 [2]. No code-level workaround exists short of the patch; users can mitigate exposure by only performing multisig operations with public keys received from trusted sources [3].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2< 1.4.0+ 1 more
- (no CPE)range: < 1.4.0
- (no CPE)
Patches
13bc449a81389Multisig: return errors instead of panicking on invalid curve points when delinearizing
12 files changed · +177 −42
keys/src/multisig/address.rs+4 −4 modified@@ -4,7 +4,7 @@ use nimiq_hash::Blake2bHasher; #[cfg(feature = "serde-derive")] use nimiq_utils::merkle::compute_root_from_content; -use super::public_key::DelinearizedPublicKey; +use super::{error::PartialSignatureError, public_key::DelinearizedPublicKey}; #[cfg(feature = "serde-derive")] use crate::Address; use crate::Ed25519PublicKey; @@ -13,14 +13,14 @@ use crate::Ed25519PublicKey; pub fn combine_public_keys( public_keys: Vec<Ed25519PublicKey>, num_signers: usize, -) -> Vec<Ed25519PublicKey> { +) -> Result<Vec<Ed25519PublicKey>, PartialSignatureError> { // Calculate combinations. let combinations = public_keys.into_iter().combinations(num_signers); let mut multisig_keys: Vec<Ed25519PublicKey> = combinations .map(|combination| DelinearizedPublicKey::sum_delinearized(&combination)) - .collect(); + .collect::<Result<_, _>>()?; multisig_keys.sort(); - multisig_keys + Ok(multisig_keys) } /// Given a list of possible public keys, generates an address for which each of the public keys is a possible signer.
keys/src/multisig/commitment.rs+10 −6 modified@@ -57,15 +57,19 @@ impl Commitment { } } -impl From<[u8; Commitment::SIZE]> for Commitment { - fn from(bytes: [u8; Commitment::SIZE]) -> Self { - Commitment::from_bytes(bytes).unwrap() +impl TryFrom<[u8; Commitment::SIZE]> for Commitment { + type Error = (); + + fn try_from(bytes: [u8; Commitment::SIZE]) -> Result<Self, Self::Error> { + Commitment::from_bytes(bytes).ok_or(()) } } -impl<'a> From<&'a [u8; Commitment::SIZE]> for Commitment { - fn from(bytes: &'a [u8; Commitment::SIZE]) -> Self { - Commitment::from(*bytes) +impl<'a> TryFrom<&'a [u8; Commitment::SIZE]> for Commitment { + type Error = (); + + fn try_from(bytes: &'a [u8; Commitment::SIZE]) -> Result<Self, Self::Error> { + Commitment::try_from(*bytes) } }
keys/src/multisig/error.rs+2 −0 modified@@ -27,4 +27,6 @@ impl std::error::Error for InvalidScalarError { pub enum PartialSignatureError { #[error("Missing nonces")] MissingNonces, + #[error("Invalid curve point in public key")] + InvalidCurvePoint, }
keys/src/multisig/mod.rs+16 −9 modified@@ -156,9 +156,9 @@ impl CommitmentsBuilder { } /// Creates the aggregate commitment and additional data for the content to be signed. - pub fn build(mut self, content: &[u8]) -> CommitmentsData { + pub fn build(mut self, content: &[u8]) -> Result<CommitmentsData, PartialSignatureError> { self.all_public_keys.sort(); - let aggregate_public_key = DelinearizedPublicKey::sum_delinearized(&self.all_public_keys); + let aggregate_public_key = DelinearizedPublicKey::sum_delinearized(&self.all_public_keys)?; let mut partial_agg_commitments = Vec::with_capacity(MUSIG2_PARAMETER_V); @@ -193,14 +193,14 @@ impl CommitmentsBuilder { agg_commitment_edwards += partial_agg_commitment.0 * scale; } - CommitmentsData { + Ok(CommitmentsData { nonces: self.nonces, commitments: self.all_commitments[0], aggregate_public_key, aggregate_commitment: Commitment(agg_commitment_edwards), all_public_keys: self.all_public_keys, b, - } + }) } } @@ -279,18 +279,22 @@ impl Ed25519PublicKey { /// Delinearizes a public key by multiplying it with a scalar derived from the hash and the public key itself. /// Effective delinearization for multisigs should use the hash over all public keys as an input. - pub(crate) fn delinearize(&self, public_keys_hash: &[u8; 64]) -> EdwardsPoint { + pub(crate) fn delinearize( + &self, + public_keys_hash: &[u8; 64], + ) -> Result<EdwardsPoint, PartialSignatureError> { // Compute H(C||P). let mut h: Sha512 = Sha512::default(); h.update(&public_keys_hash[..]); h.update(self.as_bytes()); let s = Scalar::from_hash::<Sha512>(h); - // Should always work, since we come from a valid public key. - let p = self.to_edwards_point().unwrap(); + let p = self + .to_edwards_point() + .ok_or(PartialSignatureError::InvalidCurvePoint)?; // Compute H(C||P)*P. - s * p + Ok(s * p) } pub fn verify_partial( @@ -303,7 +307,10 @@ impl Ed25519PublicKey { let public_keys_hash = hash_public_keys(&commitments_data.all_public_keys); // And delinearize them. // Note that here we delinearize as p^{H(H(pks), p)}, e.g., with an additional hash due to the function delinearize_private_key - let delinearized_public_key = self.delinearize(&public_keys_hash); + let delinearized_public_key = match self.delinearize(&public_keys_hash) { + Ok(p) => p, + Err(_) => return false, + }; // Compute c = H(R, apk, m) let mut hasher = Sha512Hasher::new();
keys/src/multisig/public_key.rs+14 −7 modified@@ -2,7 +2,10 @@ use std::{borrow::Borrow, iter::Sum}; use curve25519_dalek::{edwards::EdwardsPoint, traits::Identity}; -use crate::{multisig::hash_public_keys, Ed25519PublicKey}; +use crate::{ + multisig::{error::PartialSignatureError, hash_public_keys}, + Ed25519PublicKey, +}; /// This structure holds a delinearized public key (which prevents rogue key attacks in multisigs). #[derive(Copy, Clone)] @@ -11,14 +14,16 @@ pub struct DelinearizedPublicKey(EdwardsPoint); impl DelinearizedPublicKey { /// Delinearizes a public key by multiplying it with a scalar derived from the hash and the public key itself. /// Effective delinearization for multisigs should use the hash over all public keys as an input. - fn new(public_key: Ed25519PublicKey, hash: &[u8; 64]) -> Self { - DelinearizedPublicKey(public_key.delinearize(hash)) + fn new(public_key: Ed25519PublicKey, hash: &[u8; 64]) -> Result<Self, PartialSignatureError> { + Ok(DelinearizedPublicKey(public_key.delinearize(hash)?)) } /// Delinearizes a list of public keys and returns the list of delinearized public keys. /// Delinearizaion prevents rogue key attacks. /// Each public key is multiplied with a scalar derived from the hash over all public keys and the public key itself. - pub fn delinearize(public_keys: &[Ed25519PublicKey]) -> Vec<Self> { + pub fn delinearize( + public_keys: &[Ed25519PublicKey], + ) -> Result<Vec<Self>, PartialSignatureError> { let mut public_keys = public_keys.to_vec(); public_keys.sort(); let h = hash_public_keys(&public_keys); @@ -30,11 +35,13 @@ impl DelinearizedPublicKey { /// Delinearizes and aggregates a list of public keys. /// Delinearizaion prevents rogue key attacks. - pub fn sum_delinearized(public_keys: &[Ed25519PublicKey]) -> Ed25519PublicKey { - let d: DelinearizedPublicKey = DelinearizedPublicKey::delinearize(public_keys) + pub fn sum_delinearized( + public_keys: &[Ed25519PublicKey], + ) -> Result<Ed25519PublicKey, PartialSignatureError> { + let d: DelinearizedPublicKey = DelinearizedPublicKey::delinearize(public_keys)? .into_iter() .sum(); - d.into() + Ok(d.into()) } }
keys/tests/multisig.rs+109 −4 modified@@ -5,7 +5,9 @@ use nimiq_keys::{ multisig::{ address::{combine_public_keys, compute_address}, commitment::{Commitment, CommitmentPair, Nonce}, + error::PartialSignatureError, partial_signature::PartialSignature, + public_key::DelinearizedPublicKey, CommitmentsBuilder, }, Address, Ed25519PublicKey, KeyPair, PrivateKey, @@ -93,6 +95,13 @@ const VECTORS: [StrTestVector; 4] = [ }, ]; +/// Bytes that are NOT a valid compressed Edwards Y coordinate on Ed25519. +/// CompressedEdwardsY(INVALID_CURVE_POINT_BYTES).decompress() returns None. +const INVALID_CURVE_POINT_BYTES: [u8; 32] = [ + 0xab, 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, 0x37, +]; + #[test] fn it_can_construct_public_keys() { for vector in VECTORS.iter() { @@ -165,7 +174,7 @@ fn it_can_create_signatures() { builder = builder.with_signer(pks[j], commitments[j]); } } - let data = builder.build(&test.message); + let data = builder.build(&test.message).unwrap(); let partial_sig = key_pair.partial_sign(&data, &test.message).unwrap(); assert!( @@ -237,7 +246,8 @@ fn it_can_create_a_valid_multisignature() { let combined_public_keys = combine_public_keys( vec![keypair_a.public, keypair_b.public, keypair_c.public], 2, - ); + ) + .unwrap(); assert_eq!(compute_address(&combined_public_keys), wallet_address); let mut tx = "01f4e305f34ea1ccf00c0f7fcbc030d1347dc5eafe000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000500".to_string(); @@ -255,7 +265,8 @@ fn it_can_create_a_valid_multisignature() { commitment_pair_b_2.commitment(), ], ) - .build(&tx_content); + .build(&tx_content) + .unwrap(); assert_eq!(commitments_data_a.aggregate_public_key, signing_public_key); assert_eq!( @@ -281,7 +292,8 @@ fn it_can_create_a_valid_multisignature() { commitment_pair_a_2.commitment(), ], ) - .build(&tx_content); + .build(&tx_content) + .unwrap(); assert_eq!(commitments_data_b.aggregate_public_key, signing_public_key); assert_eq!( @@ -318,3 +330,96 @@ fn it_can_create_a_valid_multisignature() { assert_eq!(&tx, signed_transaction); } + +fn invalid_curve_point_key() -> Ed25519PublicKey { + Ed25519PublicKey::from(INVALID_CURVE_POINT_BYTES) +} + +#[test] +fn delinearize_rejects_invalid_curve_point() { + let valid_kp: KeyPair = from_hex!( + "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904", + PrivateKey::SIZE, + PrivateKey::from + ) + .into(); + let invalid_key = invalid_curve_point_key(); + + let result = DelinearizedPublicKey::sum_delinearized(&[valid_kp.public, invalid_key]); + assert!( + matches!(result, Err(PartialSignatureError::InvalidCurvePoint)), + "expected InvalidCurvePoint error, got {result:?}" + ); +} + +#[test] +fn build_rejects_invalid_public_key() { + let mut rng = test_rng(true); + let valid_kp: KeyPair = from_hex!( + "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904", + PrivateKey::SIZE, + PrivateKey::from + ) + .into(); + let invalid_key = invalid_curve_point_key(); + let pairs = CommitmentPair::generate_all(&mut rng); + + let builder = CommitmentsBuilder::with_private_commitments(valid_kp.public, pairs) + .with_signer(invalid_key, [Commitment::default(); 2]); + + let result = builder.build(b"test message"); + assert!( + matches!(result, Err(PartialSignatureError::InvalidCurvePoint)), + "expected InvalidCurvePoint error" + ); +} + +#[test] +fn verify_partial_with_invalid_key_returns_false() { + let mut rng = test_rng(true); + let valid_kp: KeyPair = from_hex!( + "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904", + PrivateKey::SIZE, + PrivateKey::from + ) + .into(); + let pairs = CommitmentPair::generate_all(&mut rng); + let commitments = CommitmentPair::to_commitments(&pairs); + + // Build valid commitments data first. + let data = CommitmentsBuilder::with_private_commitments(valid_kp.public, pairs) + .with_signer(valid_kp.public, commitments) + .build(b"test") + .unwrap(); + let partial_sig = valid_kp.partial_sign(&data, b"test").unwrap(); + + // Verifying with an invalid key should return false, not panic. + let invalid_key = invalid_curve_point_key(); + assert!(!invalid_key.verify_partial(&data, &partial_sig, b"test")); +} + +#[test] +fn commitment_try_from_rejects_invalid_bytes() { + let result = Commitment::try_from(INVALID_CURVE_POINT_BYTES); + assert!( + result.is_err(), + "expected error for invalid curve point bytes" + ); +} + +#[test] +fn combine_public_keys_rejects_invalid_key() { + let valid_kp: KeyPair = from_hex!( + "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904", + PrivateKey::SIZE, + PrivateKey::from + ) + .into(); + let invalid_key = invalid_curve_point_key(); + + let result = combine_public_keys(vec![valid_kp.public, invalid_key], 2); + assert!( + matches!(result, Err(PartialSignatureError::InvalidCurvePoint)), + "expected InvalidCurvePoint error, got {result:?}" + ); +}
wallet/src/multisig_account.rs+7 −2 modified@@ -53,7 +53,8 @@ impl MultiSigAccount { let mut sorted_public_keys = public_keys.to_vec(); sorted_public_keys.sort(); - let multi_sig_keys = combine_public_keys(sorted_public_keys, min_signatures.get() as usize); + let multi_sig_keys = + combine_public_keys(sorted_public_keys, min_signatures.get() as usize)?; Ok(Self::new(key_pair, min_signatures, &multi_sig_keys)) } @@ -109,7 +110,9 @@ impl MultiSigAccount { } /// Utility method that delinearizes and aggregates the provided slice of public keys. - pub fn aggregate_public_keys(public_keys: &[Ed25519PublicKey]) -> Ed25519PublicKey { + pub fn aggregate_public_keys( + public_keys: &[Ed25519PublicKey], + ) -> Result<Ed25519PublicKey, PartialSignatureError> { DelinearizedPublicKey::sum_delinearized(public_keys) } @@ -178,6 +181,8 @@ pub enum MultiSigAccountError { InvalidSignatureFromBytes(#[from] nimiq_keys::SignatureError), #[error("Number of signatures must be the same as the minimal signatures")] InvalidSignaturesLength, + #[error("Invalid curve point in public key")] + InvalidCurvePoint(#[from] PartialSignatureError), #[error("The public key of keypair must be part of provided public keys")] KeyPairNotPartOfList, #[error("The provided public keys must not be empty")]
wallet/tests/multisig.rs+10 −5 modified@@ -44,13 +44,15 @@ pub fn it_can_create_valid_transactions() { kp2.public, CommitmentPair::to_commitments(&commitment_pairs2), ) - .build(&transaction.serialize_content()); + .build(&transaction.serialize_content()) + .unwrap(); let data2 = CommitmentsBuilder::with_private_commitments(kp2.public, commitment_pairs2) .with_signer( kp1.public, CommitmentPair::to_commitments(&commitment_pairs1), ) - .build(&transaction.serialize_content()); + .build(&transaction.serialize_content()) + .unwrap(); assert_eq!(data1.aggregate_public_key, data2.aggregate_public_key); assert_eq!(data1.aggregate_commitment, data2.aggregate_commitment); @@ -115,9 +117,12 @@ pub fn aggregated_public_key_order_does_not_matter() { let kp2 = KeyPair::from(PrivateKey::from_hex(PRIVATE_KEYS[1]).unwrap()); let kp3 = KeyPair::from(PrivateKey::from_hex(PRIVATE_KEYS[2]).unwrap()); - let pk1 = MultiSigAccount::aggregate_public_keys(&[kp1.public, kp2.public, kp3.public]); - let pk2 = MultiSigAccount::aggregate_public_keys(&[kp2.public, kp3.public, kp1.public]); - let pk3 = MultiSigAccount::aggregate_public_keys(&[kp3.public, kp2.public, kp1.public]); + let pk1 = + MultiSigAccount::aggregate_public_keys(&[kp1.public, kp2.public, kp3.public]).unwrap(); + let pk2 = + MultiSigAccount::aggregate_public_keys(&[kp2.public, kp3.public, kp1.public]).unwrap(); + let pk3 = + MultiSigAccount::aggregate_public_keys(&[kp3.public, kp2.public, kp1.public]).unwrap(); assert_eq!(pk1, pk2); assert_eq!(pk1, pk3);
web-client/src/common/address.rs+1 −1 modified@@ -96,7 +96,7 @@ impl Address { return Err(JsError::new("No public keys provided")); } - let combined_public_keys = combine_public_keys(public_keys, num_signers); + let combined_public_keys = combine_public_keys(public_keys, num_signers)?; Ok(Address::from(compute_address(&combined_public_keys))) }
web-client/src/multisig/commitment.rs+1 −1 modified@@ -95,7 +95,7 @@ impl Commitment { builder.push_signer(public_key, commitments); }); - let commitment_data = builder.build(data); + let commitment_data = builder.build(data)?; Ok(Commitment::from(commitment_data.aggregate_commitment)) }
web-client/src/multisig/partial_signature.rs+1 −1 modified@@ -151,7 +151,7 @@ impl PartialSignature { commitments_data.push_signer(other_public_keys[i], commitments); } - let signature = own_keypair.partial_sign(&commitments_data.build(data), data)?; + let signature = own_keypair.partial_sign(&commitments_data.build(data)?, data)?; Ok(PartialSignature::from(signature)) }
web-client/src/primitives/public_key.rs+2 −2 modified@@ -101,15 +101,15 @@ impl PublicKey { num_signers: usize, ) -> Result<Vec<PublicKey>, JsError> { let keys = PublicKey::unpack_public_keys(keys)?; - let combined_keys = combine_public_keys(keys, num_signers); + let combined_keys = combine_public_keys(keys, num_signers)?; Ok(combined_keys.into_iter().map(PublicKey::from).collect()) } /// Sums public keys into one combined public key. pub fn sum(keys: &PublicKeyAnyArrayType) -> Result<PublicKey, JsError> { let keys = PublicKey::unpack_public_keys(keys)?; let combined_key = - nimiq_keys::multisig::public_key::DelinearizedPublicKey::sum_delinearized(&keys); + nimiq_keys::multisig::public_key::DelinearizedPublicKey::sum_delinearized(&keys)?; Ok(PublicKey::from(combined_key)) }
Vulnerability mechanics
Root cause
"Missing curve-point validation in Ed25519PublicKey construction allows invalid 32-byte keys to reach `.unwrap()` calls on decompression, causing a panic."
Attack vector
An attacker supplies a crafted 32-byte public key that is length-valid but does not represent a valid compressed Edwards Y coordinate on the Ed25519 curve. `Ed25519PublicKey` construction only validates byte length, not curve membership, so the invalid key passes through. When a victim wallet user initiates a multisig operation that includes this key — via `CommitmentsBuilder::build()`, `DelinearizedPublicKey::sum_delinearized()`, or `combine_public_keys()` — the delinearization path calls `.unwrap()` on a failed curve point decompression, causing a panic and crashing the hosting process (browser or desktop wallet). The attacker must convince the user to include the crafted key in a multisig setup; this is not remotely triggerable on nodes or validators.
Affected code
The vulnerability spans multiple files in the `keys/src/multisig/` module. `Ed25519PublicKey::delinearize()` in `keys/src/multisig/mod.rs` called `.unwrap()` on `self.to_edwards_point()`, which panics when the 32-byte public key does not represent a valid point on the Ed25519 curve. `Commitment::from_bytes()` in `keys/src/multisig/commitment.rs` had the same pattern via `From<[u8; 32]>`. The callers `DelinearizedPublicKey::sum_delinearized()` in `keys/src/multisig/public_key.rs` and `combine_public_keys()` in `keys/src/multisig/address.rs` propagated the panic upward.
What the fix does
The patch replaces `.unwrap()` calls with `.ok_or(PartialSignatureError::InvalidCurvePoint)?` in `Ed25519PublicKey::delinearize()` and changes `Commitment::from<[u8; 32]>` to `Commitment::try_from<[u8; 32]>` returning `Result`. All callers — `CommitmentsBuilder::build()`, `DelinearizedPublicKey::sum_delinearized()`, `combine_public_keys()`, and `MultiSigAccount::aggregate_public_keys()` — are updated to propagate the error instead of panicking. `verify_partial()` now returns `false` on invalid curve points rather than crashing. This closes the denial-of-service vector by ensuring invalid public keys produce recoverable errors instead of process-terminating panics.
Preconditions
- inputAttacker must supply a 32-byte public key that is not a valid Ed25519 curve point
- inputVictim must include the attacker-supplied key in a multisig operation (e.g., via CommitmentsBuilder::build, combine_public_keys, or sum_delinearized)
- configVictim must be using the web-client WASM library or the nimiq-wallet crate
Generated on May 21, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-h9cc-w26m-j342ghsaADVISORY
- github.com/nimiq/core-rs-albatross/commit/3bc449a8138960c4de6bfd506bad1730c621d4deghsa
- github.com/nimiq/core-rs-albatross/pull/3713ghsa
- github.com/nimiq/core-rs-albatross/releases/tag/v1.4.0ghsa
- github.com/nimiq/core-rs-albatross/security/advisories/GHSA-h9cc-w26m-j342ghsa
News mentions
0No linked articles in our index yet.