ANT-2026-KNXJMVYC · wolfssl/wolfssl

signature-bypass high

CVE-2026-5466 GHSA-47qf-hp3h-rwmm

Severity Claude high · Security research firm high · Maintainer high

Discovered by Claude Mythos Preview

REPORT

Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Calif.

ANT-2026-KNXJMVYC: Universal ECCSI signature forgery in wolfSSL wc_VerifyEccsiHash via r = 0, s = 0

wolfSSL's ECCSI (RFC 6507) signature verifier, wc_VerifyEccsiHash() in wolfcrypt/src/eccsi.c, decoded the signature components r and s from the signature buffer with mp_read_unsigned_bin() and never checked that they lie in the range [1, q-1]. A signature carrying s = 0 makes the verification point J the point at infinity, whose x-coordinate is treated as 0, and with r = 0 the final comparison of J's x-coordinate against r succeeds, so the forged signature is accepted for any message and any signer identity using only publicly known constants. The issue is CVE-2026-5466 / GHSA-47qf-hp3h-rwmm, rated High, and is fixed in wolfSSL 5.9.1.

Target

Project: wolfSSL
Location: wolfcrypt/src/eccsi.c:wc_VerifyEccsiHash (and eccsi_calc_j)
Discovery: static analysis — not yet dynamically reproduced

Technical Details

ECCSI verification (RFC 6507, section 5.2.2) in wolfSSL decodes a signature of the form r | s | PVT, computes HE = hash(HS | r | M), Y = [HS]PVT + KPAK and J = [s]([HE]G + [r]Y), and accepts the signature when the x-coordinate of J compares equal to r. In wolfcrypt/src/eccsi.c, eccsi_decode_sig_r_pvt() and eccsi_decode_sig_s() read r and s with mp_read_unsigned_bin(); before the fix, the checks applied to the signature were its length and that PVT decodes to a point on the curve. Neither r nor s was validated against [1, q-1].

With s = 0, the scalar multiplication in eccsi_calc_j() returns the point at infinity, so J's x-coordinate is 0. With r = 0, the final mp_cmp(jx, r) == MP_EQ test in wc_VerifyEccsiHash() then holds and *verified is set to 1. Because this outcome does not depend on the message or the signer identity, an attacker who supplies r = 0 and s = 0 together with a PVT that is a valid curve point obtains a signature that verifies against any message for any identity, using only publicly known constants. The code is reachable by any application that passes attacker-controlled signatures to wc_VerifyEccsiHash() in a build with ECCSI support (WOLFCRYPT_HAVE_ECCSI).

/* added in wc_VerifyEccsiHash(); an equivalent check on s is added in eccsi_calc_j() */
if (err == 0) {
    if (mp_iszero(r)) {
        err = MP_ZERO_E;
    }
    else if (mp_cmp(r, ¶ms->order) != MP_LT) {
        err = ECC_OUT_OF_RANGE_E;
    }
}

Reproduction

This finding was identified by static analysis and has not yet been dynamically reproduced. The Technical Details section above describes the code path; a trigger input is not included.

[No reproducer or sanitizer output attached — request from security-cvd@anthropic.com if needed.]

Acknowledgement

This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by the Anthropic security team in collaboration with Anthropic Research. Please direct questions to security-cvd@anthropic.com and reference ANT-2026-KNXJMVYC.


Reference: ANT-2026-KNXJMVYC
Anthropic CVD Policy: https://www.anthropic.com/coordinated-vulnerability-disclosure

SECURITY RESEARCH FIRM ANALYSIS

Triage and disclosure were performed by Calif.

Verdict
true positive
Severity
high
UPSTREAM FIX

The change that resolved this finding.

diff --git a/wolfcrypt/src/eccsi.c b/wolfcrypt/src/eccsi.c
index b4cf859e500..d919dd8a341 100644
--- a/wolfcrypt/src/eccsi.c
+++ b/wolfcrypt/src/eccsi.c
@@ -2159,6 +2159,18 @@ static int eccsi_calc_j(EccsiKey* key, const mp_int* hem, const byte* sig,
     if (err == 0) {
         err = eccsi_decode_sig_s(key, sig, sigSz, s);
     }
+    /* Validate s is in [1, q-1]: reject zero or out-of-range second signature
+     * component.  With s=0, [s](...) yields the point at infinity whose
+     * affine x-coordinate is 0, making the final mp_cmp(0,0) accept any
+     * forged signature. */
+    if (err == 0) {
+        if (mp_iszero(s)) {
+            err = MP_ZERO_E;
+        }
+        else if (mp_cmp(s, &key->params.order) != MP_LT) {
+            err = ECC_OUT_OF_RANGE_E;
+        }
+    }
     /* [s]( [HE]G + [r]Y ) */
     if (err == 0) {
         err = eccsi_mulmod_point(key, s, j, j, 1);
@@ -2238,6 +2250,19 @@ int wc_VerifyEccsiHash(EccsiKey* key, enum wc_HashType hashType,
         err = mp_montgomery_setup(&params->prime, &mp);
     }
 
+    /* Validate r is in [1, q-1]: reject zero or out-of-range first signature
+     * component before any scalar multiplication takes place.
+     * Without this check, r=0 causes J_x=0 and the final mp_cmp(0,0)==MP_EQ
+     * comparison accepts the forged signature unconditionally. */
+    if (err == 0) {
+        if (mp_iszero(r)) {
+            err = MP_ZERO_E;
+        }
+        else if (mp_cmp(r, &params->order) != MP_LT) {
+            err = ECC_OUT_OF_RANGE_E;
+        }
+    }
+
     /* Step 1: Validate PVT is on curve */
     if (err == 0) {
         err = wc_ecc_is_point(pvt, &params->a, &params->b, &params->prime);
@@ -2273,6 +2298,16 @@ int wc_VerifyEccsiHash(EccsiKey* key, enum wc_HashType hashType,
         key->params.haveBase = 0;
     }
 
+    /* Defense-in-depth: reject J = point at infinity before the final
+     * comparison. Catches any future path that might reach this point
+     * with a neutral-element result (e.g. s = 0 mod q for a non-zero
+     * encoded s). */
+    if (err == 0) {
+        if (wc_ecc_point_is_at_infinity(j)) {
+            err = ECC_INF_E;
+        }
+    }
+
     /* Step 6: Jx fitting, compare with r */
     if (err == 0) {
         jx = &key->tmp;

https://github.com/wolfSSL/wolfssl/commit/13a016367

TIMELINE

Dates from discovery through public reveal.

  1. 2026-03-29 Reported to tracker
  2. 2026-04-05 Sent to maintainer
  3. 2026-05-07 Patch released
  4. 2026-05-07 Maintainer acknowledged
  5. 2026-05-20 Publicly revealed
PROVENANCE

SHA-3-512 hash:

e4b9aa3b2e76b2e8e469e6d0bcadd5f14c9a876e667184ecf444b15e78488876b22e9c62781469f71687db5744334620cfa82068c52c47642611ed20394f2bcd

Committed 2026-04-05 16:37 PT

Revealed 2026-05-20 00:40 PT

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-KNXJMVYC",
  "bug_class": "signature-bypass",
  "claude_severity": "high",
  "commit_sha": null,
  "created_at": "2026-03-29T20:42:34+00:00",
  "description": null,
  "discovered_at": null,
  "location": null,
  "poc_sha256": null,
  "preimage_version": 1,
  "project": "wolfSSL",
  "reproduction": null,
  "technical_details": null,
  "title": "eccsi universal signature forgery via r 0 s 0 missing s",
  "vendor_severity": "high"
}