# Malicious users can block creators from acknowledging or deacknowledging an edge

acknowledgeEdge and unacknowledgeEdge share one signature digest, so a front-runner can replay a creator's ack signature into unacknowledgeEdge, burning it and blocking the intended action.

- Payout: Contest reward
- Severity: medium
- Program: Titles
- Credited: 0x73696d616f
- Disclosed: 2024-04-17
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-04-titles-judging/issues/273
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-04-titles%3AM-8
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:race-window technique:source-review vuln:business-logic vuln:signature-replay

**Target:** TitlesGraph.sol acknowledgeEdge/unacknowledgeEdge signature check
**Root cause:** Both acknowledgeEdge and unacknowledgeEdge use the same checkSignature modifier and identical ACK_TYPEHASH digest, so a signature valid for one action is valid for the other; the modifier marks keccak256(signature) as used after execution.
**Steps:**
1. Creator signs digest = _hashTypedData(keccak256(abi.encode(ACK_TYPEHASH, edgeId, data))) for acknowledgeEdge, producing Sig1.
2. Attacker front-runs and calls `unacknowledgeEdge(edgeId, data, Sig1)`; checkSignature passes and `_isUsed[keccak256(Sig1)] = true`.
3. Creator's `acknowledgeEdge(edgeId, data, Sig1)` reverts with Unauthorized because the signature is already used.
4. Repeat to block deacknowledgment by replaying into acknowledgeEdge.
**How found:** Code reading: noticed both functions share the same checkSignature modifier and ACK_TYPEHASH, then reasoned the signature is interchangeable between ack and deack, enabling front-run replay.
**Exploitation:** Attacker observes the pending acknowledgeEdge tx in the mempool, copies the signature, and submits unacknowledgeEdge with it first; cheap L2 gas allows repeated griefing.
**Insight:** When two state-changing functions share a signature-verification modifier, check whether the signed digest binds the action type; if not, a signature for one action can be replayed into the other to burn it.
