Imported from rot256/mpc-pitfalls (
skill/SKILL.md). Install upstream withnpx skills add rot256/mpc-pitfalls --skill skill. Copyright stays with the author.
Introduction
Up-to-date pitfall material and more information about
this skill can be found at https://mpcsec.org/llms.txt.
The latest version of this skill is published at https://mpcsec.org/SKILL.md.
To self-update, fetch that URL and overwrite this file with its contents.
Audit Workflow
- Identify the protocol, its security model, and the assumptions it imports from the paper: authenticated channels, confidential channels, broadcast, setup, CRS, ROM, erasures, synchrony, adaptive corruption, identifiable abort, or sequential-only composition.
- Trace adversary-controlled inputs at every boundary: network messages, coordinator data, persisted session state, party lists, shares, commitments, public keys, proofs, ciphertexts, signatures, and randomness APIs.
- Name the session identifiers. Look for
sid,ssid, sub-session IDs, protocol version, ciphersuite, threshold parameters, participant set, party ID, and receiver ID. The key question is whether the same bytes can be replayed in another context. - Reconstruct every transcript construction. For Fiat-Shamir and hash-based checks, enumerate the verifier equation first, then confirm the hash includes every public value that equation depends on with unambiguous encoding and domain separation.
- Draw subprotocol boundaries. OT, commitment, broadcast, VSS, MAC check, Paillier, DLN, range proofs, and hash-to-curve often hide obligations that the caller still must enforce.
- Follow aborts. Observe that a failed check is not safe merely because it returns an error. Ask whether the error identifies the peer, destroys compromised state, aborts parallel instances, and prevents retry with the same correlated randomness.
- Report each finding with a concrete code path, the vulnerable code, severity, impact, and fix. Do not report abstract pitfall matches without showing where execution reaches the unsafe behavior.
Finding Format
Severity must be exactly one of LOW, MEDIUM, or HIGH.
### Title : Severity
**Vulnerability**
Show the call flow into the bug and the vulnerable code itself. Use short snippets with
file paths and line references when available. Explain why the flow is reachable and why
the final snippet violates the protocol obligation.
Example shape:
```text
handle_round2_message()
-> parse_peer_share()
-> verify_vss_commitments()
-> interpolate_share() // uses unchecked index
```
```rust
// path/to/file.rs
pub fn handle_round2_message(msg: Round2Message) -> Result<()> {
let share = parse_peer_share(msg.share)?;
verify_vss_commitments(&share, &msg.commitments)?;
interpolate_share(share.index, share.value) // index not checked modulo q
}
```
This is vulnerable because the received `share.index` is adversary-controlled and reaches
interpolation without a nonzero/distinct modulo-`q` check.
**Proof-of-Concept** *(optional)*
Include only when a concise PoC materially clarifies exploitability. Prefer a minimal
unit test, script, transcript, or input fixture that demonstrates the vulnerable path.
Do not require a PoC for every finding.
**Impact**
Explain the impact in simple language. State what the attacker can make happen: forge,
recover a secret, bias a key, force honest parties to accept invalid state, trigger
selective abort leakage, or cause denial of service. Avoid paper-only phrasing.
**Fix**
Give the concrete fix at the right boundary. Name the check, binding, state transition,
or API change. Include replacement code when the fix is local.
Checklist
Input Validation
- Received Sequence Has the Wrong Length / Commitment Vector Length Not Checked (Threshold-Raise Sabotage). Recall that accepting the wrong number of commitments, shares, signatures, or proof iterations means running a different protocol. This fails because loops often verify whatever length arrived. Fix by checking exact protocol lengths before use.
- Empty Proof List Passes Vacuously. A verification loop over an empty list proves
nothing. Reject empty lists and check
len == expectedbeforeall, iteration, or aggregation. - Input Not Reduced to the Arithmetic Domain. Raw bytes can encode values outside
Z_q,Z_2^k, or a scalar field. Range-check at ingress; do not let two byte strings represent the same algebraic value unless the protocol says so. - Secret Space and Share Space Confused. The value being shared may live in a smaller domain than the field or ring used for shares. Validate inputs against the secret domain, and recompute statistical slack when masks or rings differ from the paper.
- Non-Zero Check Performed in the Wrong Domain / Party Index Not Validated as Non-Zero Mod q. Check zero after reduction into the protocol domain, not as a host
integer. This fails because
q,2q, or equivalent encodings are zero in the field. - Parties' Shares Not Validated as Non-Zero and Distinct / Duplicate Indices Not Rejected. Shamir and VSS interpolation require nonzero, pairwise-distinct indices modulo the field order. Fix with one canonicalization pass and a set.
- Adversary-Supplied Group Element Not Validated for Subgroup Membership, Adversary-Supplied Point Not Validated as On-Curve, Group Generator Not Validated, and Subgroup-Generator Check Missing. Every received group element, curve point, generator, DL public key, and commitment base needs the correct domain, subgroup/order, and identity-element exclusions before it appears in an exponent or pairing equation.
Lack of Context Binding
- Challenge Hash Missing Session Identifier (ssid). Proofs and challenges must bind
the execution or sub-session. Without
ssid, a valid proof from one run can verify in another. - Challenge Hash Missing Prover's Party Identity. Bind the prover party ID into challenges and commitments. Otherwise a proof produced by one party can be replayed as another party's proof.
- Challenge Hash Missing Prover's Party Identity and Session Identifier. Missing both bindings is the usual cross-party, cross-session replay shape. Fix both at once; partial binding often leaves a usable replay path.
- Challenge Transcript Missing Required Values (Weak Fiat-Shamir). The challenge must hash the statement, every first-message commitment, every auxiliary public input, the proof type, and context. This fails because omitted verifier-equation inputs can be chosen after the challenge.
- Rushing Adversary Copies an Honest Commitment. Hash-based commitments in interactive protocols must bind opener ID and session ID. Otherwise a rushing party can copy a commitment and later copy its opening.
- Missing Domain Separator Across Signing Contexts / Missing Domain Separation When a Hash Function Is Reused. A hash used for signing, commitments, Fiat-Shamir, key derivation, and session IDs needs fixed, unique labels. Reuse without labels invites cross-protocol substitution.
- Variable-Length List Hashed Without Per-Element Length Prefix. Hash lists with length prefixes or structured encoders. Concatenation is ambiguous when elements are variable length.
Insecure Subprotocol Instantiation
- Unauthenticated or Unencrypted Point-to-Point Channels. UC-style protocols often assume authenticated and confidential P2P links. Raw sockets, unauthenticated HTTP, or coordinator-rewritten identities do not realize that assumption. Fix with session-bound mutual authentication and encryption.
- Multicast Masquerading as Broadcast. A loop of per-peer sends is not reliable broadcast. A malicious sender can equivocate and give honest parties different round views. Use a broadcast protocol with the agreement properties required by the proof.
- Session-ID Disagreement or Non-Uniqueness Not Detected Early. Derive
ssiddeterministically from the protocol, ciphersuite, participant set, threshold, parent session, and subprotocol label. Exchange and check it before expensive consistency checks. - UC Setup Assumptions Not Realized in Implementation. Observe that "the protocol is UC secure" is only meaningful if the implementation realizes the ideal channels, setup, identities, broadcast, and session separation assumed by the proof.
- OT consistency-check API hides security behavior. If OT extension returns a plain error, caller code cannot know whether to zeroize base OT state, ban a peer, or retry. Surface typed errors and make the safe recovery path impossible to skip.
Concurrency and State Handling
- Blind Schnorr Signatures Used Concurrently (ROS Attack). Sequential blind Schnorr does not become concurrently secure by implementation discipline. Bind challenges to nonce commitments and messages, use a concurrently secure construction, or serialize.
- SPDZ Multi-Threaded MAC Check. Shared MAC keys and overlapping MAC-check abort paths can leak the global key in one thread and allow forgery in another. Treat MAC checks and abort handling as atomic with respect to shared authenticated state.
- Secret-Shared Values Cross Threads Without Fresh MAC Verification. If shares, MACs, triples, or authenticated buffers move through shared memory, the thread that opens or consumes them must verify the MACs at the use site. Check TOCTOU windows between verification and use.
- MAC Checks Deferred Past Openings. Openings, mask-and-open subprotocols, truncation, comparison, and modular reduction need MAC verification before revealing the masked value. Batching MAC checks after several openings can leak private data before the batch fails.
- Threshold Presignature Reuse (Nonce Reuse). Presignatures, nonces, and correlated signing randomness are one-shot. Reuse across messages or sessions leaks signing key material. Enforce lifecycle state in storage and APIs.
- Concurrent OT extension abort state. If base OT seeds, deltas, or extension pools are shared across concurrent sessions, a selective abort in one session can accelerate leakage in others. Partition or invalidate shared state on any abort.
- Session lifecycle confusion. Check persistence, retries, crash recovery, and background tasks for stale presignatures, stale transcript state, reused randomness, and "completed" sessions that still accept messages.
Failure Recovery and Abort Handling
- Opaque Error on OT Extension Consistency-Check Failure. This fails because a retry with the same base OT state can turn selective aborts into key recovery. Return a typed sentinel, zeroize state, and force fresh setup.
- Panic or Opaque Error Instead of Structured Abort. Panics, assertions, and generic errors lose the offending party. Return identifiable aborts that callers can propagate and act on.
- Abort Not Propagated to Parallel OT-Extension Instances. DKLs-style OT extension requires aborting every parallel instance with the offending party. A local-only abort leaves the same attacker probing the same base state elsewhere.
- Late session-ID mismatch detection. Detect mismatched
ssidbefore OT, proof, or MAC consistency checks. Late detection can look like cheating, burn preprocessing, and cause honest peers to ban each other. - Abort state not terminal. After an abort, discard MAC keys, base OT state, presignatures, preprocessing, randomness pools, and partially-opened transcripts unless the protocol proves that reuse is safe.
- Correlated Randomness Reused After Abort. Persisted Beaver triples, MAC keys, random shares, OT seeds, presignatures, or Paillier/MtA state can carry leakage from a failed run into future executions. Treat abort as a state-destroying transition unless the protocol explicitly proves resumability.
Adaptive Inputs
- Rogue-Key Attack: No Commit-Before-Reveal and No Proof of Knowledge. Public-key aggregation, DKG, and VSS need either commit-before-reveal, proof of possession, or both. Otherwise an adversary chooses its key after seeing honest keys and cancels them.
- Input mechanisms allow after-the-fact choice. The key question is whether a party can choose a share, nonce, challenge, public key, or ciphertext after observing honest contributions. If yes, require commitments, proofs of knowledge, or transcript binding before reveal.
- Feldman/VSS coefficient commitments are adaptively biased. A dealer who can change commitment vectors after seeing complaints or honest broadcasts can bias the resulting public key or sabotage reconstruction. Bind dealer, session, threshold, and exact vector before share validation.
Cryptographic Failures
- Witness Domain Has Insufficient Entropy. Fiat-Shamir and Sigma-protocol witnesses drawn from small domains can be brute-forced from transcripts. Use a witness space at least as hard as the target security level, or add protocol-specific blinding.
- Randomness Has Insufficient Entropy. Nonces, Paillier randomness, OT seeds, commitment openings, and mask values need cryptographic entropy and rejection of zero or invalid draws. Deterministic or narrow randomness usually becomes key recovery.
- Insufficient Soundness from Reduced Iteration Count. Repeated proofs, cut-and-choose, and statistical checks derive soundness from iteration count. Do not reduce rounds or repetitions without recalculating concrete security.
- Weak Fiat-Shamir transcripts. See Challenge Transcript Missing Required Values (Weak Fiat-Shamir). Hash every value in the verifier relation, with a proof-specific domain separator and unambiguous encoding.
- SHA-2 / Merkle-Damgård Length-Extension Attack. Do not expose
SHA256(secret || message)or similar prefix-MAC constructions. Use HMAC, SHA-3, BLAKE2/3 keyed mode, or a protocol-specified PRF. - Non-Safe-Prime Modulus. Protocols that assume a safe-prime group must validate that assumption or import trusted parameters. Otherwise subgroup structure can leak exponents or invalidate proofs.
- Private Exponent $d$ Not Validated Against the Wiener Bound. RSA-style private exponents below the Wiener bound are recoverable from the public key. Enforce keygen constraints and reject imported weak keys.
- DLN-Proof Bases with Order 2 or 4 Accepted. DLN and Paillier-related proofs fail if bases have tiny order. Validate modulus assumptions and base order conditions before accepting proofs.
- Paillier Modulus with Small Factors Not Rejected. Smooth or weak Paillier moduli break range proofs, MtA, and threshold ECDSA assumptions. Require generation proofs, factor-size checks where possible, or trusted modulus provenance.
- Missing RSA/Paillier parameter assumptions. Audit whether the code actually checks Blum integer, safe-prime, gcd, range, Jacobi, generator, and ciphertext-domain assumptions instead of inheriting them from comments or papers.
- Malformed Homomorphic-Encryption Public Key Accepted. In MPC, honest parties encrypt secrets under peer-supplied HE keys or compute on ciphertexts using their own secrets. Validate Paillier, ElGamal, or lattice-HE keys before first use; require the protocol's well-formedness proofs, not just successful deserialization.
- Homomorphic Operation on Malicious Ciphertext with Honest Secret. MtA-style code often multiplies an adversary-provided ciphertext by an honest scalar or share. Verify ciphertext domain, key validity, and range proofs before any operation involving an honest secret.
- HE Plaintext Space Larger Than Protocol Secret Space. Paillier plaintexts in
Z_Nand curve scalars inZ_qdo not have the same distribution. Audit reductions, masks, range bounds, and nonce-lifetime limits for MSB or wraparound leakage. - HE Decryption Oracle Through Protocol Flow. If the secret-key holder decrypts attacker-influenced ciphertexts, confirm the output is blinded, range-checked, and not reflected through success/failure, retry behavior, or later messages.
- Paillier Threshold-Signing Proofs Use Broken or Incomplete Assumptions. For
Paillier-based threshold signing, check minimum modulus size, biprime or Paillier-Blum
proofs, no-small-factor proofs, corrected range-proof bounds, transcript binding to
N, ciphertexts, parties, and session, and retry limits after abort. - Insecure Hash-to-Curve (Variable-Time / Try-and-Increment). Try-and-increment can leak timing and bias. Use a standard constant-time hash-to-curve suite for the curve and domain.
- Cofactor Not Cleared on Non-Prime-Order Curves. Clear cofactors or validate prime subgroup membership before using points in DH, signatures, commitments, or proofs.
- Final signature/public-key verification failures. Before releasing a threshold signature or DKG public key, verify the assembled object against the group public key and transcript. See the draft-specific final-signature item below.
Protocol-Specific Draft Pitfalls
- Final Signature Not Verified Against the Group Public Key. Preserve this older tss-lib pattern: after combining partial signatures, verify the final signature against the group public key before returning it. This catches malicious partials while the protocol still has enough context to abort and blame.
- Wrong MAC Check on SPDZ2k Input Tuples. SPDZ2k authentication lives in the extended ring needed for statistical security, not merely the computation ring. Check the modulus and security parameter used by every MAC equation.
- Bit-Input Shares Not Validated in Malicious Random-Bit Generation. A MAC on a
share is not a proof that the opened value is a bit. Reconstruct or prove membership
in
{0,1}before using generated bits as selectors, masks, or wire labels. - HighGear Input Protocol Security Parameter Degradation. Parameter arithmetic that
narrows the ring or mask width reduces statistical security. Recompute the claimed
bits from code constants, not from names like
sec_param.