Secp256k1 Signature Malleability
Detects Secp256k1 signature verification without canonicalization checks.
Secp256k1 Signature Malleability
Overview
The Secp256k1 signature malleability detector identifies when Secp256k1 signature verification (used for Ethereum compatibility on Solana) is performed without proper canonicalization checks. For every valid ECDSA signature (r, s), another valid signature (r, -s mod n) exists for the same message. This enables signature replay attacks if signatures are used as unique identifiers.
For remediation guidance, see Secp256k1 Signature Malleability Remediation.
Why This Is an Issue
Secp256k1 is used on Solana primarily for Ethereum signature verification via the secp256k1_recover syscall. If a program uses signatures as unique identifiers (e.g., in a nonce/replay mapping), an attacker can produce an alternate valid signature for the same message and bypass the uniqueness check. This enables double-spending, replay attacks, and authorization bypass.
How to Resolve
Before (Vulnerable)
// Vulnerable: no low-S check
pub fn verify_eth_sig(sig: &[u8; 64], msg: &[u8; 32], expected: &[u8; 20]) -> ProgramResult {
let recovered = secp256k1_recover(msg, sig[64], sig)?;
let addr = eth_address_from_pubkey(&recovered);
require!(addr == expected, InvalidSignature);
Ok(())
}
After (Fixed)
// Fixed: enforce low-S canonical form
pub fn verify_eth_sig(sig: &[u8; 64], msg: &[u8; 32], expected: &[u8; 20]) -> ProgramResult {
// Enforce low-S: s must be <= SECP256K1_N / 2
let s = &sig[32..64];
require!(is_low_s(s), NonCanonicalSignature);
let recovered = secp256k1_recover(msg, sig[64], sig)?;
let addr = eth_address_from_pubkey(&recovered);
require!(addr == expected, InvalidSignature);
Ok(())
}
Example JSON Finding
{
"detector": "secp256k1-signature-malleability",
"severity": "medium",
"confidence": 0.6,
"message": "Secp256k1 signature verification without low-S canonicalization check",
"location": { "function": "verify_eth_sig", "block": 0, "statement": 1 }
}
Detection Methodology
- Secp256k1 syscall detection: Identifies
secp256k1_recoversyscall usage. - Low-S check search: Looks for comparisons of the S component against the curve half-order.
- Signature uniqueness tracking: Flags signature-based uniqueness checks without canonicalization.
- Signature storage detection: Identifies programs that store signatures for replay prevention.
Limitations
False positives: Programs where signature malleability has no security impact (no uniqueness requirement). False negatives: Custom ECDSA implementations not using the syscall.
Related Detectors
- Signature Replay — general signature replay attacks