Date: 2026-04-11 Target: github.com/fireblocks/mpc-lib (main branch) Platform: Bugcrowd Status: ALL POCs VERIFIED, AWAITING REVIEW BEFORE SUBMISSION
Verified Findings
| # | Finding | Severity | PoC Status | Key Evidence |
|---|---|---|---|---|
| 03 | 8-bit batch verification randomness (type confusion) | P2 | VERIFIED, forgery proven | 7/2000 trials pass (0.35%, expected 0.39%) |
| 02 | Destructor heap overflow (OPENSSL_cleanse sizeof) | P2 | VERIFIED, 320 bytes overwritten | sizeof(struct)=352 vs sizeof(k.data)=32 |
| 04 | Fiat-Shamir truncates proof.A | P3 | VERIFIED, hash unchanged on upper modification | Upper 256 bytes of A unbound in challenge |
| 05 | Integer overflow in quadratic ZKP deser | P3 | VERIFIED, size check bypassed | 4.3GB required → passes with 373 bytes |
| 08 | Asymmetric EdDSA unsalted commitment | P3 | VERIFIED, 10000/10000 collisions | Deterministic vs randomized comparison |
| 06 | Unbounded alloca() stack overflow | P3 | Source confirmed | Guard present in sibling function, missing here |
| 07 | Missing sig verify offline ECDSA | P3 | Source confirmed | Online path verifies, offline does not |
| 01 | Ring Pedersen degenerate params | P4 | VERIFIED, but NOT exploitable | CMP uses verifier’s own params; no attack path |
PoC Results
Finding 03, Batch Forgery (THE MONEY SHOT)
[3] 5 valid + 1 INVALID proof, gamma_invalid = 0 (forced):
Pass rate: 200/200 ← gamma=0 makes ANY invalid proof invisible!
[4] 5 valid + 1 INVALID, random 8-bit gamma (realistic attack):
Pass rate: 7/2000 = 0.35% (expected: 1/256 = 0.39%)
[5] 5 valid + 1 INVALID, gamma ∈ [1,255] (excluding 0):
Pass rate: 0/2000 (expect ~0 - gamma=0 excluded)
Proven: When gamma_k=0 (P=1/256), the invalid proof contributes E^0S^0=1 and 0(anything)=0 to the batch equation, completely invisible regardless of proof validity.
Finding 02, Destructor Overflow
sizeof(elliptic_curve256_scalar_t) = 32 (k.data)
sizeof(ecdsa_preprocessing_data) = 352 (entire struct)
Overflow: 320 bytes past k.data are zeroed by OPENSSL_cleanse
Finding 05, Integer Overflow Size Check Bypass
uint32_t computation: 4 + 9*0x1C71C71D + 2*132 = 273 (OVERFLOWED!)
True required size: 4.3 GB
proof_len(373) >= expected(273)? YES - BYPASSED!
Submission Strategy
Submit #1: Finding 03 (8-bit batch gamma), Target P1
- Type confusion:
uint8_t[16]vsuint64_t[2] - Developer comments prove intent (“// 40bits”)
- Batch verification bypass proven mathematically AND empirically
- Exploitation: 256 signing sessions → range proof bypass → MTA manipulation
- Full PoC: batch-forgery-proof.cpp + mta-batch-8bit-gamma.cpp
Submit #2: Finding 02 (destructor overflow), P2/P3
OPENSSL_cleanse(k.data, sizeof(ecdsa_preprocessing_data))overwrites 320 bytes- Two instances (ECDSA + EdDSA asymmetric)
- Memory corruption on every signing cleanup
- PoC: destructor-overflow-v2.cpp
Submit #3: Findings 04+05 bundle, P3
- Fiat-Shamir truncation + integer overflow
- Both have clear PoC demonstrations
- PoCs: fiat-shamir-truncation.cpp + integer-overflow-bypass-proof.c
Submit #4: Findings 06+07+08 bundle, P3/P4
- alloca + missing sig verify + unsalted commitment
- Lower severity but clear bugs
Files
findings/
00-SUMMARY.md ← This file
01-ring-pedersen-degenerate-params-P4.md
02-destructor-heap-overflow-P2.md
03-mta-batch-verification-8bit-randomness-P2.md
04-fiat-shamir-truncation-mta-P3.md
05-integer-overflow-quadratic-zkp-deser-P3.md
06-alloca-stack-overflow-range-proofs-P3.md
07-offline-ecdsa-no-sig-verify-P3.md
08-eddsa-unsalted-commitment-P3.md
poc/ (all compile and run clean)
01-ring-pedersen-degenerate.c → poc-ring-pedersen (in findings dir)
02-destructor-overflow-v2.cpp → poc-destructor-v2 ✅
03-batch-forgery-proof.cpp → poc-batch-forgery ✅ (MAIN POC)
03-mta-batch-8bit-gamma.cpp → poc-gamma ✅
03-mta-batch-8bit-gamma.py → python3 script ✅
04-fiat-shamir-truncation.cpp → poc-fiat-shamir ✅
05-integer-overflow-bypass-proof.c → poc-overflow-bypass ✅
08-unsalted-commitment.cpp → poc-unsalted ✅
Source · github.com/zionsworking/security-research-notebook · writeups/fireblocks/00-SUMMARY.md