Skip to main content
Sigvex

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

  1. Secp256k1 syscall detection: Identifies secp256k1_recover syscall usage.
  2. Low-S check search: Looks for comparisons of the S component against the curve half-order.
  3. Signature uniqueness tracking: Flags signature-based uniqueness checks without canonicalization.
  4. 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.

References