CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-22699
7.50.17%

Panic at the Crypto-Disco: CVE-2026-22699 in RustCrypto

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 23, 2026·6 min read·5 visits

PoC Available

Executive Summary (TL;DR)

The RustCrypto SM2 implementation contained a logic flaw where invalid ciphertext inputs were unwrapped without validation. An attacker can send a syntactically correct but mathematically invalid elliptic curve point, causing the library to panic and the application to crash (DoS).

In the world of Rust, memory safety is the golden calf. We don't worry about buffer overflows or dangling pointers anymore. Instead, we worry about developers getting lazy with error handling. CVE-2026-22699 is a textbook example of 'Panic-Driven Development' within the `sm2` crate of the RustCrypto ecosystem. By sending a malformed elliptic curve point during decryption, an attacker can trigger an unhandled `.unwrap()`, crashing the application instantly. It's a classic Denial of Service that proves even the safest languages can't save you from logic bombs.

The Hook: When Standards Collide with Reality

SM2 is the 'chosen one' of Chinese cryptography standards. It's an elliptic curve algorithm used for encryption, signatures, and key exchange, mandating its own specific curve parameters. If you're doing business in China or interacting with Chinese financial systems, you aren't using NIST P-256; you're using SM2.

The RustCrypto ecosystem is generally excellent—a collection of pure Rust implementations of common cryptographic algorithms. It's the building block for secure communications in thousands of Rust applications. But here is the thing about cryptography libraries: they are complex, math-heavy, and absolutely intolerant of bad input.

This vulnerability sits inside the sm2 crate, specifically in the Public Key Encryption (PKE) decryption logic. The issue isn't a complex side-channel attack or a mathematical break of the discrete log problem. It's much stupider than that. It's the coding equivalent of walking a tightrope without a net because you're 'pretty sure' you won't fall.

The Flaw: The Sin of Unwrap

In Rust, the .unwrap() method is a way of telling the compiler: 'Trust me, I know what I'm doing. This value will never be null (None). If it is, feel free to kill the entire thread.' It is the 'Hold My Beer' of the Rust programming language.

The vulnerability lies in how the library handles the $C1$ component of the ciphertext. An SM2 ciphertext is essentially a concatenation of three parts: a random elliptic curve point ($C1$), a hash digest ($C3$), and the encrypted data ($C2$). When the library receives a ciphertext, it has to parse $C1$ back into an actual coordinate $(x, y)$ on the elliptic curve.

The library correctly parses the bytes. However, just because you have a set of bytes that looks like a point (correct length, correct headers) doesn't mean those coordinates actually fall on the specific curve defined by SM2 ($y^2 = x^3 + ax + b$). If the point isn't on the curve, the math fails.

The developers handled the parsing, but when it came to the validity check, they got lazy. They assumed that if the bytes were formatted correctly, the point must be valid. When the validation function returns None (indicating the point is off-curve), the code calls .unwrap(), triggering an immediate panic. In a server context, this means the request handler dies. If the server isn't robust against thread panics, the whole process dies.

The Code: Autopsy of a Panic

Let's look at the crime scene in sm2/src/pke/decrypting.rs. The vulnerable code takes the encoded $C1$ bytes and tries to turn them into an AffinePoint.

The Vulnerable Code:

// The developer assumes this will always succeed if bytes are correct
let mut c1_point = AffinePoint::from_encoded_point(&encoded_c1).unwrap();

The method from_encoded_point performs the curve equation check. It returns a CtOption (Constant-Time Option), which is a cryptographic primitive designed to prevent timing attacks. It doesn't return a standard Rust Option, but it behaves similarly. If the check fails, it wraps a 'failure' state. Calling .unwrap() on a failed CtOption creates a panic.

The Fix (Commit 085b7be):

// The fix: Convert to Option, then Result, and bubble up the error
let mut c1_point = AffinePoint::from_encoded_point(&encoded_c1)
    .into_option() // Convert CtOption to standard Option
    .ok_or(Error)?; // Return Error if None, instead of crashing

The fix is trivial but critical. Instead of crashing the program, the library now returns a graceful Error. The calling application sees this as a 'decryption failed' event rather than a 'process terminated' event.

The Exploit: Crashing the Party

Exploiting this does not require a supercomputer or a degree in number theory. You just need to be able to do basic arithmetic—or rather, bad arithmetic.

To construct the exploit payload:

  1. Generate a valid point: Start with a valid SM2 public key point to get the byte length and header format correct (uncompressed points usually start with 0x04).
  2. Corrupt the coordinates: Change the last byte of the $x$ or $y$ coordinate. By changing a single bit, the probability that the new random coordinate pair $(x', y')$ still satisfies the curve equation $y'^2 = x'^3 + ax' + b$ is astronomically low.
  3. Construct Ciphertext: Assemble the fake SM2 ciphertext structure: [Invalid C1 Point] || [Random C3 Hash] || [Random C2 Ciphertext].
  4. Send it: Submit this blob to any endpoint expecting SM2-encrypted data.

When the victim application parses the blob, it sees the 0x04 header and says, 'Ah, an uncompressed point.' It reads the coordinates. It runs the curve equation check. The check fails. The library returns None. The code calls .unwrap(). BOOM. The thread unwinds, the stack is dumped, and the service stops responding.

The Impact: Why Denial of Service Matters

Critics might say, 'It's just a DoS, not Remote Code Execution.' While true, in the context of the Rust ecosystem, this is embarrassing. Rust is sold on reliability. If a single malformed packet can take down your high-performance, memory-safe web server, you have failed the assignment.

For financial gateways or authentication servers using SM2 (common in Chinese banking integrations), this is a high-severity issue. An attacker can loop this request to keep the service permanently offline, preventing legitimate transactions. No data is stolen, but business grinds to a halt.

Furthermore, because this panic happens inside a cryptographic library, it often occurs deep in the call stack, potentially bypassing higher-level catch_unwind blocks if the developer didn't anticipate panics from their crypto primitive.

The Mitigation: Patch and Audit

The fix is already available in the RustCrypto repository. If you are using elliptic-curves or the sm2 crate, you need to update immediately.

Remediation Steps:

  1. Update Dependencies: Run cargo update to pull the latest patch versions. Specifically, look for sm2 versions patched after Jan 9, 2026 (Commit 085b7be).
  2. Audit Your Code: Search your own codebase for .unwrap() or .expect(). If you are handling user input—even indirectly via a library—an unwrap() is a ticking time bomb.
  3. Monitor Logs: If you cannot patch immediately, ensure your service supervisor (systemd, k8s) is configured to restart the service instantly upon crash. Set up alerting for process exits with code 101 (Rust panic).

This vulnerability serves as a reminder: Memory safety does not equal logic safety. You can write perfectly memory-safe code that is still fragile as glass.

Official Patches

RustCryptoGitHub Commit Diff

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.17%
Top 62% most exploited

Affected Systems

Rust applications using `sm2` crateRustCrypto `elliptic-curves` library usersSystems implementing Chinese National Standard GM/T 0003

Affected Versions Detail

Product
Affected Versions
Fixed Version
sm2 (crate)
RustCrypto
<= 0.14.0-rc.0Commit 085b7be
elliptic-curves
RustCrypto
<= 0.14.0-rc.0Commit 085b7be
AttributeDetail
CWECWE-20 (Improper Input Validation)
CVSS v3.17.5 (High)
Attack VectorNetwork
ImpactDenial of Service (DoS)
LanguageRust
Componentsm2::pke::decrypting

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1499Endpoint Denial of Service
Impact
CWE-20
Improper Input Validation

Known Exploits & Detection

TheorySending an encoded point that does not satisfy y^2 = x^3 + ax + b triggers panic.

Vulnerability Timeline

Vulnerability reported by XlabAITeam
2026-01-09
Fix committed to main branch
2026-01-09
GHSA and CVE published
2026-01-10

References & Sources

  • [1]GHSA Advisory
  • [2]NVD Entry

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.