# Duplicate registration without uniqueness check

Insertion or registration paths that never check whether the key, entry, or tracker already exists

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; latest 2025-03-20. Updated 2026-10-24._

## How it works
A function that adds a record (a linked-list node, a tracker entry, a deposit entry) assumes the new key is distinct from what is already stored. When that assumption is false, the write either overwrites a pointer that already points at the same key, or appends a second entry for a key that should be unique. The data structure then no longer matches its own invariant: a node points to itself, an entry index repeats, or a stale record persists. Iteration over the structure then hangs, double-counts, or keeps re-processing the same item.

## Where it shows up
- Sorted linked-list insertion that compares only against the *next* node, not the current/prior node [E1](https://bugbountylibrary.com/r/cantina%3Aterm_structure_february2025%3A3.1.7.md)
- Mapping writes where the same key can be both the new node and its predecessor [E1](https://bugbountylibrary.com/r/cantina%3Aterm_structure_february2025%3A3.1.7.md)
- Permissionless "add" handlers with no already-processed / already-registered lookup [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md)
- Cleanup that runs only on the success path, leaving failed entries in place [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md)
- Batch loops validating an aggregate sum (`msg.value`) but not each element for nonzero [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AH-2.md)
- Entry-index counters incremented only on some branches [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AH-2.md)

## How to review
For every insert/register path, state the uniqueness invariant explicitly: which key must be unique, and where is that enforced? Check that the comparison covers *all* neighbours the new key could equal, including the head/prior node, not just the next one [E1](https://bugbountylibrary.com/r/cantina%3Aterm_structure_february2025%3A3.1.7.md). For permissionless adders, confirm a dedup or executed-check exists before storage, and that removal happens on failure too, not only success [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md). For batch functions, verify each element is validated individually, not just the total [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AH-2.md). The property that must hold: after any call, no key appears twice and no node references itself.

## Variants seen
- Self-referential linked-list node from equality with the prior maturity [E1](https://bugbountylibrary.com/r/cantina%3Aterm_structure_february2025%3A3.1.7.md)
- Re-adding an already-executed inbound tracker, re-voted forever by observers [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md)
- Zero-amount deposit creating duplicate entry indexes [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AH-2.md)

## Impact and severity
Led to broken interest accrual and denial of service on new orders [E1](https://bugbountylibrary.com/r/cantina%3Aterm_structure_february2025%3A3.1.7.md), network congestion from endless re-voting [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md), and corrupted winner selection [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AH-2.md). Severity rises when the path is permissionless and the bad entry is never cleaned up, since anyone can amplify it repeatedly [E2](https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md).

## Evidence
- E1: https://bugbountylibrary.com/r/cantina%3Aterm_structure_february2025%3A3.1.7.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-29.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AH-2.md
