Severity: P2 (High), Memory corruption in signing hot path
Summary
Two struct destructors use sizeof(entire_struct) instead of sizeof(scalar_field) as the length for OPENSSL_cleanse(), causing a 320-byte heap overwrite past the intended 32 bytes. This corrupts STL container internals (std::vector, std::map) before their destructors run, causing undefined behavior on every signing session cleanup.
Locations
Instance 1: ecdsa_preprocessing_data
- File:
include/cosigner/cmp_ecdsa_signing_service.h, line 85 - sizeof(k.data): 32 bytes
- sizeof(ecdsa_preprocessing_data): 352 bytes
- Overwrite: 320 bytes past k.data
~ecdsa_preprocessing_data() {OPENSSL_cleanse(k.data, sizeof(ecdsa_preprocessing_data));}
Instance 2: asymmetric_eddsa_signature_data
- File:
include/cosigner/asymmetric_eddsa_cosigner_server.h, line 33
~asymmetric_eddsa_signature_data() {OPENSSL_cleanse(k.data, sizeof(asymmetric_eddsa_signature_data));}
Impact
- Fires on EVERY ECDSA and asymmetric EdDSA signing operation
- Zeroes STL container internals (vector pointers, map tree nodes) before destructors run
- Memory leak: heap allocations for vector/map data never freed
- UB per C++ standard: destructors operate on corrupted state
- In long-running MPC signing service: gradual memory exhaustion → DoS
PoC
poc/02-destructor-overflow-v2.cpp, demonstrates the 352 vs 32 mismatch and leaked allocations.
Remediation
~ecdsa_preprocessing_data() {
OPENSSL_cleanse(&k, sizeof(elliptic_curve256_scalar_t) * 6 + sizeof(elliptic_curve256_point_t));
}
Source · github.com/zionsworking/security-research-notebook · writeups/fireblocks/02-destructor-heap-overflow-P2.md