CVE-2026-24850: Ml dsa ML-DSA Signature Verification Accepts Signatures Vulnerability

MODERATE
Advisory Identifier: GHSA-5x2r-hc65-25f9
CVSS 5.3
CWE-347
Published
Advisory Summary

CVE-2026-24850 is a MODERATE (CVSS 5.3) ml-dsa signature verification accepts signatures vulnerability (CWE-347: Improper Verification of Cryptographic Signature) affecting Ml dsa libraries in the crates.io ecosystem. The issue involves ml-dsa signature verification accepts signatures with repeated hint indices. Remediation is available by upgrading affected packages to version 0.1.0-rc.4.

CVE-2026-24850 at a Glance

CVE Identifier CVE-2026-24850
GHSA Identifier GHSA-5x2r-hc65-25f9
Severity MODERATE
CVSS v3.1 Base Score 5.3
CWE Classification CWE-347: Improper Verification of Cryptographic Signature
Affected Product Ml dsa
Package Ecosystem crates.io
Published Date
Last Updated

Security Impact

CVSS: 5.3

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-24850

To remediate this vulnerability, upgrade all affected Ml dsa dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

ml-dsa fixed: 0.1.0-rc.4
Upgrade ml-dsa to 0.1.0-rc.4
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for ml-dsa

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-24850, inspect your project dependencies for Ml dsa:

inspect dependencies for ml-dsa

Analyze the terminal output to locate any version of Ml dsa in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.1.0-rc.4), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-347: Improper Verification of Cryptographic Signature, where the product does not verify, or incorrectly verifies, the cryptographic signature for data. In Ml dsa, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

**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`: ```rust 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 (`<`): ```rust 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`](https://gist.github.com/orenyomtov/fb4616eb77d33017f41a71b30aa41a04) 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](https://github.com/C2SP/wycheproof/blob/master/testvectors_v1/mldsa_44_verify_test.json) - 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: ```rust 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 to prevent it**: 1. **FIPS 204 Specification:** ML-DSA is designed to be strongly unforgeable under chosen message attacks (SUF-CMA). This security property explicitly prevents signature malleability. 2. **NIST PQC Forum Discussion:** In February 2024, there was a discussion on the NIST PQC forum about potential malleability in ML-DSA's hint unpacking. The consensus was that ML-DSA is intended to be SUF-CMA, meaning any malleability issues should be considered bugs and fixed. 3. **No Documentation of Intentional Malleability:** There is no documentation in the RustCrypto `ml-dsa` crate, FIPS 204, or RFC 9881 suggesting that signature malleability is an acceptable or intentional property. 4. **Regression Bug:** The fact that the original implementation had strict ordering (`<`) and this was changed to non-strict (`<=`) in a "fix" commit suggests this was an unintentional regression, not a design decision.

CVE-2026-24850 Affected Ml dsa Versions

1 component(s)
Fixed Versions:
0.1.0-rc.4
Product / Package Ecosystem Affected Versions Fixed Version
ml-dsa
crates.io
≥ 0.0.4
< 0.1.0-rc.4
0.1.0-rc.4

References

Frequently Asked Questions

What is CVE-2026-24850?
CVE-2026-24850 is a security vulnerability in Ml dsa involving ML-DSA Signature Verification Accepts Signatures with Repeated Hint Indices under CWE-347: Improper Verification of Cryptographic Signature.
Which Ml dsa versions are affected?
Affected versions include releases prior to 0.1.0-rc.4 across affected packages: ml-dsa.
What version fixes CVE-2026-24850?
Upgrading to 0.1.0-rc.4 (or the latest patched release for your respective branch) resolves the vulnerability.
Is ml-dsa affected?
Yes, ml-dsa is affected in releases prior to 0.1.0-rc.4. Upgrade your dependency to 0.1.0-rc.4 or later.
What is the CVSS score of CVE-2026-24850?
CVE-2026-24850 has a CVSS v3.1 base score of 5.3 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N.
What CWE is associated with CVE-2026-24850?
CVE-2026-24850 is classified under CWE-347: Improper Verification of Cryptographic Signature (The product does not verify, or incorrectly verifies, the cryptographic signature for data.).
How can I check crates.io dependencies for CVE-2026-24850?
Run the dependency tree command: 'inspect dependencies for ml-dsa'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-5x2r-hc65-25f9",
  "modified" : "2026-01-28T16:44:47Z",
  "published" : "2026-01-28T16:44:47Z",
  "aliases" : [ "CVE-2026-24850" ],
  "summary" : "ML-DSA Signature Verification Accepts Signatures with Repeated Hint Indices",
  "details" : "**Affected Crate:** `ml-dsa`  \n**Affected Versions:** v0.1.0-rc.2 (and commits since `b01c3b7`)  \n**Severity:** Medium  \n**Reporter:** Oren Yomtov (Fireblocks)\n\n## Summary\n\nThe 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.\n\n**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.\n\n## Vulnerability Details\n\n### Root Cause\n\nThe vulnerability is located in the `monotonic` helper function in `ml-dsa/src/hint.rs`:\n\n```rust\nfn monotonic(a: &[usize]) -> bool {\n    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] <= *x)\n}\n```\n\nThe comparison operator `<=` allows equal consecutive values, meaning duplicate hint indices are not rejected. The correct implementation should use strict less-than (`<`):\n\n```rust\nfn monotonic(a: &[usize]) -> bool {\n    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] < *x)\n}\n```\n\n### Regression Analysis\n\n- **Original correct code** (commit `1d3a1d1` - \"Add support for ML-DSA (#877)\"): Used `<` (strict)\n- **Bug introduced** (commit `b01c3b7` - \"Make ML-DSA signature decoding follow the spec (#895)\"): Changed to `<=`\n\nThe 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.\n\n### Technical Impact\n\nThis 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.\n\nPer 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:\n\n1. **Signature Malleability:** Multiple distinct byte sequences verify as valid for the same message/key pair\n2. **Protocol-Level Vulnerabilities:** Systems that rely on signature uniqueness (e.g., for transaction deduplication, replay protection, or signature-based identifiers) may be vulnerable\n3. **Interoperability Issues:** Non-compliant signatures may be rejected by other conforming implementations\n\n### Affected Security Levels\n\nAll ML-DSA parameter sets are affected:\n- ML-DSA-44 (NIST Security Level 2)\n- ML-DSA-65 (NIST Security Level 3)\n- ML-DSA-87 (NIST Security Level 5)\n\n## Proof of Concept\n\nSee the file [`poc_mldsa_repeated_hint.rs`](https://gist.github.com/orenyomtov/fb4616eb77d33017f41a71b30aa41a04) for a standalone proof of concept that demonstrates the vulnerability.\n\nThe PoC uses test vectors from the Wycheproof test suite that specifically test for this invalid encoding:\n\n- **Test Vector Source:** [Wycheproof ML-DSA Test Vectors](https://github.com/C2SP/wycheproof/blob/master/testvectors_v1/mldsa_44_verify_test.json)\n- Test Case ID 18: \"signature with a repeated hint\"\n- Expected Result: `invalid`\n- Actual Result: `valid` (BUG)\n\n## Remediation\n\nUpdate the `monotonic` function in `ml-dsa/src/hint.rs` to use strict less-than comparison:\n\n```rust\nfn monotonic(a: &[usize]) -> bool {\n    a.iter().enumerate().all(|(i, x)| i == 0 || a[i - 1] < *x)\n}\n```\n\n## Design Intent: ML-DSA is NOT Intended to Allow Malleability\n\nWhile some cryptographic libraries intentionally permit signature malleability for compatibility or performance reasons, **ML-DSA is explicitly designed to prevent it**:\n\n1. **FIPS 204 Specification:** ML-DSA is designed to be strongly unforgeable under chosen message attacks (SUF-CMA). This security property explicitly prevents signature malleability.\n\n2. **NIST PQC Forum Discussion:** In February 2024, there was a discussion on the NIST PQC forum about potential malleability in ML-DSA's hint unpacking. The consensus was that ML-DSA is intended to be SUF-CMA, meaning any malleability issues should be considered bugs and fixed.\n\n3. **No Documentation of Intentional Malleability:** There is no documentation in the RustCrypto `ml-dsa` crate, FIPS 204, or RFC 9881 suggesting that signature malleability is an acceptable or intentional property.\n\n4. **Regression Bug:** The fact that the original implementation had strict ordering (`<`) and this was changed to non-strict (`<=`) in a \"fix\" commit suggests this was an unintentional regression, not a design decision.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "crates.io",
      "name" : "ml-dsa"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0.0.4"
      }, {
        "fixed" : "0.1.0-rc.4"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/RustCrypto/signatures/security/advisories/GHSA-5x2r-hc65-25f9"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-24850"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/RustCrypto/signatures/issues/894"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/RustCrypto/signatures/pull/895"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/RustCrypto/signatures/commit/400961412be2e2ab787942cf30e0a9b66b37a54a"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/RustCrypto/signatures/commit/b01c3b73dd08d0094e089aa234f78b6089ec1f38"
  }, {
    "type" : "WEB",
    "url" : "https://csrc.nist.gov/pubs/fips/204/final"
  }, {
    "type" : "WEB",
    "url" : "https://datatracker.ietf.org/doc/html/rfc9881"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/C2SP/wycheproof"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/C2SP/wycheproof/blob/master/testvectors_v1/mldsa_44_verify_test.json"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/C2SP/wycheproof/blob/master/testvectors_v1/mldsa_65_verify_test.json"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/C2SP/wycheproof/blob/master/testvectors_v1/mldsa_87_verify_test.json"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/RustCrypto/signatures"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-347" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-01-28T16:44:47Z",
    "nvd_published_at" : "2026-01-28T01:16:15Z"
  }
}