| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Convex.ThreatModel.DuplicateListEntry
Contents
Description
Threat model for detecting duplicate list entry vulnerabilities.
A Duplicate List Entry Attack exploits validators that don't check for uniqueness in list fields. The attack duplicates entries in list fields within the datum, which may reveal that the validator allows duplicate entries where uniqueness should be enforced.
Consequences ==
- Signature bypassing: In a multisig contract with
signed_userslist, an attacker can sign once and duplicate their entry to fill all required signature slots, bypassing the multi-party requirement. - Vote manipulation: In a voting contract, a single voter could have their vote counted multiple times if the voter list isn't checked for duplicates.
- Reward gaming: In reward distribution, a single participant could claim multiple reward shares by appearing multiple times in a beneficiary list.
Vulnerable Patterns ==
Pattern: No uniqueness check on signed_users ===
// Vulnerable: only checks length, not uniqueness! expect list.length(output.signed_users) >= required_signatures
An attacker who is allowed to sign can sign once, then intercept the transaction and duplicate their signature to fill all slots.
Pattern: Prepend-only list update without duplicate check ===
// Vulnerable: just prepends without checking if already in list let new_signed = list.push(input.signed_users, signer) expect output.signed_users == new_signed
The validator checks that the signer was prepended correctly, but doesn't check if the signer was already in the list. Multiple Sign transactions with the same signer create duplicates.
Mitigation ==
A secure validator should:
- Check for uniqueness before adding to lists:
!list.has(signed_users, new_signer) - Validate that list entries are unique in the output datum
- Use sets instead of lists where uniqueness is required
This threat model tests if a script output with an inline datum still validates when list entries are duplicated.
Synopsis
Duplicate list entry attack
duplicateListEntryAttack :: ThreatModel () Source #
Check for missing uniqueness checks in list fields.
For a transaction with script outputs containing inline datums:
- Recursively find all non-empty
ScriptDataListfields in the datum - Duplicate the first entry of each list
- If the transaction still validates, the script doesn't enforce uniqueness in list fields.
This catches vulnerabilities where validators allow duplicate entries
in lists like signed_users, voters, or beneficiaries where
uniqueness should be enforced.
duplicateListEntryAttack -- Duplicate first entry in all lists
duplicateFirstEntry :: ScriptData -> ScriptData Source #
Recursively duplicate the first entry in all non-empty list fields.
For ScriptDataList (x:xs), returns ScriptDataList (x:x:xs) - duplicating
the first entry.
Recursively processes ScriptDataConstructor fields, nested lists, and maps.
For other ScriptData variants (Number, Bytes) and empty lists, returns
the value unchanged.
This simulates an attack where:
- A user signs a multisig, adding their PKH to signed_users = [pkh]
- The attacker duplicates to signed_users = [pkh, pkh], filling 2 slots with 1 signature