CVEReports
CVEReports

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

Product

  • Home
  • 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-23966
9.10.01%

Curving the Bullet: How Missing Math in sm-crypto Leaked Private Keys

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 15, 2026·6 min read·13 visits

PoC Available

Executive Summary (TL;DR)

The `sm-crypto` library (used for Chinese National Standard algorithms) failed to verify if ECC points belonged to the correct curve. Attackers can send malicious points on 'weak' curves to the decryption function, calculate the private key modulo small numbers, and reconstruct the full key, breaking all confidentiality and integrity.

A critical vulnerability in the popular `sm-crypto` library allows attackers to recover private keys via Invalid Curve Attacks. By failing to validate that incoming public keys and ciphertext points actually reside on the specified elliptic curve, the library performs arithmetic operations on weak, attacker-controlled curves. This enables a classic side-channel attack where the private key is leaked in small chunks and reconstructed using the Chinese Remainder Theorem.

The Hook: National Standards vs. JavaScript Reality

In the world of cryptography, implementation details are everything. You can have the mathematically strongest algorithm on the planet—which SM2 (the Chinese National Standard equivalent to ECDSA/ECDH) claims to be—but if you implement it in JavaScript and forget the safety rails, you're asking for trouble.

sm-crypto is the de facto library for Node.js and browser environments needing to support SM2, SM3, and SM4 algorithms. It's widely used in applications that interact with Chinese financial systems, government portals, or any system adhering to GM/T standards. It's the bridge between modern web apps and national compliance.

But here's the catch: implementing Elliptic Curve Cryptography (ECC) is notoriously difficult. Unlike RSA, where the math is mostly big integer modular arithmetic, ECC relies on point addition and scalar multiplication on specific curves. CVE-2026-23966 is a textbook example of what happens when developers assume input data is benevolent. The library assumed that any point passed to it for decryption was a valid point on the SM2 curve. It was not.

The Flaw: Trusting the Math Blindly

To understand this vulnerability, you need a quick refresher on ECC. An elliptic curve is defined by an equation, typically $y^2 = x^3 + ax + b$. The security of the system relies on the "hard" problem of finding the private key $d$ given a public point $Q = dG$, where $G$ is a base point on the curve.

The SM2 decryption process involves the receiver using their private key $d$ to multiply a point $C_1$ provided by the sender ($S = [d]C_1$). The flaw in sm-crypto was strictly a logic error: it never checked if the point $C_1$ provided by the sender actually satisfied the equation $y^2 = x^3 + ax + b$ for the standard SM2 parameters.

Why does this matter? The point addition formulas used in ECC generally only depend on the parameter $a$, not $b$. If an attacker provides a point that lies on a different curve (one with the same $a$ but a different $b$), the library will happily perform the multiplication $d * C_1$ on that invalid curve. These invalid curves often have much smaller orders (fewer points), making the discrete logarithm problem trivial to solve. This is known as an Invalid Curve Attack.

The Code: The Smoking Gun

The fix is surprisingly simple, which highlights how glaring the omission was. The developers simply added a validation step before processing the input. Below is the critical diff from src/sm2/index.js.

Before the fix, the code blindly decoded the hex string into a point object and started crunching numbers. It was like accepting a package and opening it without checking the shipping label.

// VULNERABLE CODE (Before)
// The code takes the ciphertext (encryptData), extracts C1, and uses it.
const c1 = _.getGlobalCurve().decodePointHex('04' + encryptData.substr(0, 128))
// ... proceeds to use c1 in scalar multiplication with private key ...

After the fix, they invoke _.verifyPublicKey, which asserts that the point actually satisfies the curve equation.

// FIXED CODE (Commit b1c824e5)
const c1 = _.getGlobalCurve().decodePointHex('04' + encryptData.substr(0, 128))
 
// The Shield: Verify the point is actually on the curve
+ if (!c1 || !_.verifyPublicKey('04' + encryptData.substr(0, 128))) {
+   return output === 'array' ? [] : ''
+ }

They also patched the signature verification logic to ensure the signer's public key $P_A$ is valid and that signature components $r, s$ are within the valid range $[1, n-1]$. This prevents similar shenanigans during signature verification.

The Exploit: Chinese Remainder Theorem to the Rescue

So, how does an attacker actually steal the private key? It's not a one-shot exploit; it's an interactive interrogation of the server.

Step 1: Curve Selection The attacker generates a series of "invalid" curves. These curves share the $a$ parameter with the SM2 curve but have different $b$ parameters. The attacker specifically chooses curves where the number of points (the order) contains small prime factors (e.g., 3, 5, 7, ...).

Step 2: The Probe The attacker sends a ciphertext where the $C_1$ point lies on one of these weak curves. The server computes $S = [d]C_1$. If the decryption "succeeds" (or fails in a specific way that indicates the math worked but the padding/hash check failed), the attacker learns $d \pmod{\text{small_order}}$.

Step 3: Reconstruction By repeating this process with many different weak curves, the attacker collects a set of congruences: $d \equiv r_1 \pmod{p_1}$ $d \equiv r_2 \pmod{p_2}$ ... Using the Chinese Remainder Theorem (CRT), the attacker stitches these small pieces of information together to reconstruct the exact private key $d$. It's elegant, mathematical, and devastatingly effective.

The Impact: Total System Compromise

The severity of this vulnerability cannot be overstated. We are talking about Private Key Recovery. This isn't just about decrypting one message; it's about owning the identity of the receiver.

  1. Retroactive Decryption: If the system does not employ Perfect Forward Secrecy (PFS), the attacker can decrypt all past traffic they have captured.
  2. Impersonation: With the private key, the attacker can sign arbitrary data. In the context of SM2, which is often used for digital signatures in banking and government ID systems, this allows for forging transaction authorizations or official documents.
  3. Man-in-the-Middle: The attacker can transparently intercept and modify traffic, as they can now terminate TLS/SSL connections (if SM2 is used for the handshake) or decrypt application-layer payloads.

The Mitigation: Patch and Rotate

The immediate fix is to upgrade sm-crypto to version 0.3.14 or later. This version includes the necessary point validation checks.

However, patching is not enough if you suspect your endpoint has been exposed to the public internet. Because this attack recovers the private key, you must assume your current keys are compromised.

Remediation Steps:

  1. Upgrade: npm install sm-crypto@latest.
  2. Revoke: Revoke all current SM2 certificates and keys used with the vulnerable library.
  3. Rotate: Generate fresh private keys.
  4. Audit: Check logs for an unusually high number of decryption failures or "bad padding" errors, which might indicate an active exploitation attempt prior to patching.

Official Patches

JuneAndGreenOfficial patch commit on GitHub

Fix Analysis (1)

Technical Appendix

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

Affected Systems

Node.js applications using sm-crypto < 0.3.14Web browsers using sm-crypto < 0.3.14 for client-side encryptionSystems implementing GM/T (GuoMi) standards via JavaScript

Affected Versions Detail

Product
Affected Versions
Fixed Version
sm-crypto
JuneAndGreen
< 0.3.140.3.14
AttributeDetail
CWE IDCWE-345
Attack VectorNetwork
CVSS Score9.1 (Critical)
ImpactPrivate Key Recovery
Exploit StatusPoC Available (Theoretical)
EPSS Score0.00007

MITRE ATT&CK Mapping

T1552.004Unsecured Credentials: Private Keys
Credential Access
T1040Network Sniffing
Credential Access
CWE-345
Insufficient Verification of Data Authenticity

Insufficient Verification of Data Authenticity

Known Exploits & Detection

AcademicPractical Invalid Curve Attacks on TLS-ECDH

Vulnerability Timeline

Patch committed to GitHub
2026-01-20
Vulnerability Disclosed / CVE Assigned
2026-01-22
GHSA Advisory Published
2026-01-22

References & Sources

  • [1]GitHub Advisory GHSA-pgx9-497m-6c4v
  • [2]NVD Entry for CVE-2026-23966

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.