From e12d9eb7eba41a0c746f9a27fe532c3eac0db8eb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:14:58 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20Fi?= =?UTF-8?q?x=20Ed25519=20signature=20malleability=20using=20verify=5Fstric?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced `ed25519_dalek`'s standard `verify` with `verify_strict` to prevent signature malleability issues and ensure strict RFC 8032 compliance. Co-authored-by: euxaristia <25621994+euxaristia@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ crates/gitlawb-attest/src/attestation.rs | 5 +++-- crates/gitlawb-core/src/identity.rs | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..03214071 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-08-11 - Use `verify_strict` for Ed25519 signature verification +**Vulnerability:** Signature malleability in Ed25519 signatures due to `verify` instead of `verify_strict`. +**Learning:** `ed25519-dalek` provides a standard `verify` method that doesn't strictly adhere to RFC 8032 requirements for non-malleability, leading to multiple valid signatures for the same message. +**Prevention:** Use `verify_strict` when verifying Ed25519 signatures using `ed25519-dalek` to ensure RFC 8032 compliance. diff --git a/crates/gitlawb-attest/src/attestation.rs b/crates/gitlawb-attest/src/attestation.rs index 5adc7411..097cc86d 100644 --- a/crates/gitlawb-attest/src/attestation.rs +++ b/crates/gitlawb-attest/src/attestation.rs @@ -16,7 +16,7 @@ //! by exact match. use base64::{engine::general_purpose::URL_SAFE_NO_PAD as B64U, Engine}; -use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; +use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::error::{Error, Result}; @@ -111,7 +111,8 @@ impl Attestation { .try_into() .map_err(|_| Error::Signature("signature must be 64 bytes".to_string()))?; let sig = Signature::from_bytes(&sig_bytes); - vk.verify(&bytes, &sig) + // Sentinel: Use verify_strict to prevent signature malleability (RFC 8032 compliance) + vk.verify_strict(&bytes, &sig) .map_err(|e| Error::Signature(format!("ed25519: {e}")))?; Ok(vk) diff --git a/crates/gitlawb-core/src/identity.rs b/crates/gitlawb-core/src/identity.rs index 511e1203..425376d9 100644 --- a/crates/gitlawb-core/src/identity.rs +++ b/crates/gitlawb-core/src/identity.rs @@ -78,10 +78,10 @@ impl Keypair { /// Verify an Ed25519 signature. pub fn verify(verifying_key: &VerifyingKey, msg: &[u8], sig_bytes: &[u8; 64]) -> Result<()> { - use ed25519_dalek::Verifier; let sig = Signature::from_bytes(sig_bytes); + // Sentinel: Use verify_strict to prevent signature malleability (RFC 8032 compliance) verifying_key - .verify(msg, &sig) + .verify_strict(msg, &sig) .map_err(|_| Error::SignatureInvalid) }