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
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).
- Impact: universal signature forgery / improper verification of cryptographic signature (CWE-347). Severity High (CVSS v3.1 base score 8.1 as recorded in the GitHub Advisory Database).
- Identifiers: CVE-2026-5466, GHSA-47qf-hp3h-rwmm.
- Fix: commit
13a016367ff4b4d3cc4c9bc2bfdfe692a512dd81("eccsi: fix universal signature forgery via r=0/s=0"), merged via wolfSSL PR #10102 and released in wolfSSL 5.9.1. The patch adds[1, q-1]range checks for r (inwc_VerifyEccsiHash(), after the curve parameters are loaded) and for s (ineccsi_calc_j(), aftereccsi_decode_sig_s()), returningMP_ZERO_EorECC_OUT_OF_RANGE_Eand mirroring the existingwc_ecc_check_r_s_range()checks, and adds a defense-in-depth rejection of J = point at infinity (ECC_INF_E) before the final comparison.
/* 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
Triage and disclosure were performed by Calif.
- Verdict
- true positive
- Severity
- high
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(¶ms->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, ¶ms->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, ¶ms->a, ¶ms->b, ¶ms->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
Dates from discovery through public reveal.
- 2026-03-29 Reported to tracker
- 2026-04-05 Sent to maintainer
- 2026-05-07 Patch released
- 2026-05-07 Maintainer acknowledged
- 2026-05-20 Publicly revealed
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"
}