Every CVE Search/ Get API key

CVE-2026-24850

ML-DSA Signature Verification Accepts Signatures with Repeated Hint Indices

5.3 MediumFix available

The ML-DSA crate is a Rust implementation of the Module-Lattice-Based Digital Signature Standard (ML-DSA). Starting in version 0.0.4 and prior to version 0.1.0-rc.4, the ML-DSA signature verification implementation in the RustCrypto ml-dsa crate incorrectly accepts signatures with repeated (duplicate) hint indices. According to the ML-DSA specification (FIPS 204 / RFC 9881), hint indices within each polynomial must be strictly increasing. The current implementation uses a non-strict monotonic check (<= instead of <), allowing duplicate indices. This is a regression bug. The original implementation was correct, but a commit in version 0.0.4 inadvertently changed the strict < comparison to <=, introducing the vulnerability. Version 0.1.0-rc.4 fixes the issue.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
Low
Availability
None

Exploit likelihood

0.34%Up 0.3 points since Jan 28, 2026
90%50%10%1%

What each source reports

CVE List Score used 5.3

ML-DSA Signature Verification Accepts Signatures with Repeated Hint Indices

The ML-DSA crate is a Rust implementation of the Module-Lattice-Based Digital Signature Standard (ML-DSA). Starting in version 0.0.4 and prior to version 0.1.0-rc.4, the ML-DSA signature verification implementation in the RustCrypto ml-dsa crate incorrectly accepts signatures with repeated (duplicate) hint indices. According to the ML-DSA specification (FIPS 204 / RFC 9881), hint indices within each polynomial must be strictly increasing. The current implementation uses a non-strict monotonic check (<= instead of <), allowing duplicate indices. This is a regression bug. The original implementation was correct, but a commit in version 0.0.4 inadvertently changed the strict < comparison to <=, introducing the vulnerability. Version 0.1.0-rc.4 fixes the issue.

Record
CVE-2026-24850
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-347
Updated
2026-11-02
EUVDEUVD-2026-4910 5.3

The ML-DSA crate is a Rust implementation of the Module-Lattice-Based Digital Signature Standard (ML-DSA). Starting in version 0.0.4 and prior to version 0.1.0-rc.4, the ML-DSA signature verification implementation in the RustCrypto ml-dsa crate incorrectly accepts signatures with repeated (duplicate) hint indices. According to the ML-DSA specification (FIPS 204 / RFC 9881), hint indices within each polynomial must be strictly increasing. The current implementation uses a non-strict monotonic check (<= instead of <), allowing duplicate indices. This is a regression bug. The original implementation was correct, but a commit in version 0.0.4 inadvertently changed the strict < comparison to <=, introducing the vulnerability. Version 0.1.0-rc.4 fixes the issue.

Record
EUVD-2026-4910
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-5x2r-hc65-25f9 5.3

ML-DSA Signature Verification Accepts Signatures with Repeated Hint Indices

Affected Crate: ml-dsa
Affected Versions: v0.1.0-rc.2 (and commits since b01c3b7)
Severity: Medium
Reporter: Oren Yomtov (Fireblocks)

Summary

The ML-DSA signature verification implementation in the RustCrypto ml-dsa crate incorrectly accepts signatures with repeated (duplicate) hint indices. According to the ML-DSA specification (FIPS 204 / RFC 9881), hint indices within each polynomial must be strictly increasing. The current implementation uses a non-strict monotonic check (<= instead of <), allowing duplicate indices.

Note: This is a regression bug. The original implementation was correct, but commit b01c3b7 ("Make ML-DSA signature decoding follow the spec (#895)", fixing issue #894) inadvertently changed the strict < comparison to <=, introducing the vulnerability.

Vulnerability Details

Root Cause

The vulnerability is located in the monotonic helper function in ml-dsa/src/hint.rs:

fn monotonic(a: &[usize]) -> bool {
    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] <= *x)
}

The comparison operator <= allows equal consecutive values, meaning duplicate hint indices are not rejected. The correct implementation should use strict less-than (<):

fn monotonic(a: &[usize]) -> bool {
    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] < *x)
}

Regression Analysis

  • Original correct code (commit 1d3a1d1 - "Add support for ML-DSA (#877)"): Used < (strict)
  • Bug introduced (commit b01c3b7 - "Make ML-DSA signature decoding follow the spec (#895)"): Changed to <=

The commit message suggests it was intended to fix issue #894 and make decoding follow the spec, but the change to the monotonic function was in the wrong direction. The other changes in that commit (to use_hint function) may have been correct, but this specific change introduced signature malleability.

Technical Impact

This vulnerability allows signature malleability - the same logical signature can have multiple valid byte-level encodings. An attacker can take a valid signature and create additional "valid" signatures by duplicating hint indices.

Per the ML-DSA specification (FIPS 204, Section 6.2 and Algorithm 26 HintBitUnpack), hint indices must be strictly increasing to ensure a unique, canonical encoding. Accepting non-canonical signatures can lead to:

  1. Signature Malleability: Multiple distinct byte sequences verify as valid for the same message/key pair
  2. Protocol-Level Vulnerabilities: Systems that rely on signature uniqueness (e.g., for transaction deduplication, replay protection, or signature-based identifiers) may be vulnerable
  3. Interoperability Issues: Non-compliant signatures may be rejected by other conforming implementations

Affected Security Levels

All ML-DSA parameter sets are affected:

  • ML-DSA-44 (NIST Security Level 2)
  • ML-DSA-65 (NIST Security Level 3)
  • ML-DSA-87 (NIST Security Level 5)

Proof of Concept

See the file poc_mldsa_repeated_hint.rs for a standalone proof of concept that demonstrates the vulnerability.

The PoC uses test vectors from the Wycheproof test suite that specifically test for this invalid encoding:

  • Test Vector Source: Wycheproof ML-DSA Test Vectors
  • Test Case ID 18: "signature with a repeated hint"
  • Expected Result: invalid
  • Actual Result: valid (BUG)

Remediation

Update the monotonic function in ml-dsa/src/hint.rs to use strict less-than comparison:

fn monotonic(a: &[usize]) -> bool {
    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] < *x)
}

Design Intent: ML-DSA is NOT Intended to Allow Malleability

While some cryptographic libraries intentionally permit signature malleability for compatibility or performance reasons, **ML-DSA is explicitly designed…

Record
GHSA-5x2r-hc65-25f9
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-347
Updated
2026-11-02
NVD 5.3

The ML-DSA crate is a Rust implementation of the Module-Lattice-Based Digital Signature Standard (ML-DSA). Starting in version 0.0.4 and prior to version 0.1.0-rc.4, the ML-DSA signature verification implementation in the RustCrypto ml-dsa crate incorrectly accepts signatures with repeated (duplicate) hint indices. According to the ML-DSA specification (FIPS 204 / RFC 9881), hint indices within each polynomial must be strictly increasing. The current implementation uses a non-strict monotonic check (<= instead of <), allowing duplicate indices. This is a regression bug. The original implementation was correct, but a commit in version 0.0.4 inadvertently changed the strict < comparison to <=, introducing the vulnerability. Version 0.1.0-rc.4 fixes the issue.

Record
CVE-2026-24850
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-347
Updated
2026-11-02
OSV 5.3

ML-DSA Signature Verification Accepts Signatures with Repeated Hint Indices

The ML-DSA crate is a Rust implementation of the Module-Lattice-Based Digital Signature Standard (ML-DSA). Starting in version 0.0.4 and prior to version 0.1.0-rc.4, the ML-DSA signature verification implementation in the RustCrypto ml-dsa crate incorrectly accepts signatures with repeated (duplicate) hint indices. According to the ML-DSA specification (FIPS 204 / RFC 9881), hint indices within each polynomial must be strictly increasing. The current implementation uses a non-strict monotonic check (<= instead of <), allowing duplicate indices. This is a regression bug. The original implementation was correct, but a commit in version 0.0.4 inadvertently changed the strict < comparison to <=, introducing the vulnerability. Version 0.1.0-rc.4 fixes the issue.

Record
CVE-2026-24850
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-347
Updated
2026-11-02
OSVGHSA-5x2r-hc65-25f9 5.3

ML-DSA Signature Verification Accepts Signatures with Repeated Hint Indices

Affected Crate: ml-dsa
Affected Versions: v0.1.0-rc.2 (and commits since b01c3b7)
Severity: Medium
Reporter: Oren Yomtov (Fireblocks)

Summary

The ML-DSA signature verification implementation in the RustCrypto ml-dsa crate incorrectly accepts signatures with repeated (duplicate) hint indices. According to the ML-DSA specification (FIPS 204 / RFC 9881), hint indices within each polynomial must be strictly increasing. The current implementation uses a non-strict monotonic check (<= instead of <), allowing duplicate indices.

Note: This is a regression bug. The original implementation was correct, but commit b01c3b7 ("Make ML-DSA signature decoding follow the spec (#895)", fixing issue #894) inadvertently changed the strict < comparison to <=, introducing the vulnerability.

Vulnerability Details

Root Cause

The vulnerability is located in the monotonic helper function in ml-dsa/src/hint.rs:

fn monotonic(a: &[usize]) -> bool {
    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] <= *x)
}

The comparison operator <= allows equal consecutive values, meaning duplicate hint indices are not rejected. The correct implementation should use strict less-than (<):

fn monotonic(a: &[usize]) -> bool {
    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] < *x)
}

Regression Analysis

  • Original correct code (commit 1d3a1d1 - "Add support for ML-DSA (#877)"): Used < (strict)
  • Bug introduced (commit b01c3b7 - "Make ML-DSA signature decoding follow the spec (#895)"): Changed to <=

The commit message suggests it was intended to fix issue #894 and make decoding follow the spec, but the change to the monotonic function was in the wrong direction. The other changes in that commit (to use_hint function) may have been correct, but this specific change introduced signature malleability.

Technical Impact

This vulnerability allows signature malleability - the same logical signature can have multiple valid byte-level encodings. An attacker can take a valid signature and create additional "valid" signatures by duplicating hint indices.

Per the ML-DSA specification (FIPS 204, Section 6.2 and Algorithm 26 HintBitUnpack), hint indices must be strictly increasing to ensure a unique, canonical encoding. Accepting non-canonical signatures can lead to:

  1. Signature Malleability: Multiple distinct byte sequences verify as valid for the same message/key pair
  2. Protocol-Level Vulnerabilities: Systems that rely on signature uniqueness (e.g., for transaction deduplication, replay protection, or signature-based identifiers) may be vulnerable
  3. Interoperability Issues: Non-compliant signatures may be rejected by other conforming implementations

Affected Security Levels

All ML-DSA parameter sets are affected:

  • ML-DSA-44 (NIST Security Level 2)
  • ML-DSA-65 (NIST Security Level 3)
  • ML-DSA-87 (NIST Security Level 5)

Proof of Concept

See the file poc_mldsa_repeated_hint.rs for a standalone proof of concept that demonstrates the vulnerability.

The PoC uses test vectors from the Wycheproof test suite that specifically test for this invalid encoding:

  • Test Vector Source: Wycheproof ML-DSA Test Vectors
  • Test Case ID 18: "signature with a repeated hint"
  • Expected Result: invalid
  • Actual Result: valid (BUG)

Remediation

Update the monotonic function in ml-dsa/src/hint.rs to use strict less-than comparison:

fn monotonic(a: &[usize]) -> bool {
    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] < *x)
}

Design Intent: ML-DSA is NOT Intended to Allow Malleability

While some cryptographic libraries intentionally permit signature malleability for compatibility or performance reasons, **ML-DSA is explicitly designed…

Record
GHSA-5x2r-hc65-25f9
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-347
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
ml-dsa
crates.io
0.0.4 up to 0.1.0-rc.4
0.1.0-rc.4

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-24850 is a medium vulnerability (CVSS 5.3) in Rustcrypto Signatures, published January 28, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 27th percentile. Fixed in ml-dsa 0.1.0-rc.4.

References

Show 9 moreShow less
This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open