# In Project.setComplete(), the signature can be reused when the first call is reverted for some reason

Project.setComplete() reuses a previously approved signature after the first call reverts, letting a subcontractor complete a task against the builder's wishes.

- Payout: Contest reward
- Severity: medium
- Program: Rigor Protocol
- Credited: hansfriese
- Disclosed: 2022-09-12
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-08-rigor-findings/issues/263
- Library page: https://bugbountylibrary.com/r/c4%3A2022-08-rigor%3AM-13
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity vuln:business-logic vuln:signature-replay

**Target:** Solidity Project contract setComplete/approveHash signature flow
**Root cause:** approveHash() can only set approvedHashes to true and there is no way to revoke an approved hash, so a signature remains valid indefinitely even after the intended call reverts.
**Steps:**
1. Builder, GC, SC agree and sign approval for setComplete() hash.
2. Before setComplete() executes, SC calls `raiseDispute()` to change order/cost.
3. setComplete() reverts (ongoing dispute or unallocated funds).
4. Admin accepts dispute, cost increased.
5. SC calls `setComplete()` again with the same previously approved signature; it succeeds and task completes without extra work.
6. Builder cannot revoke: `updateTaskHash()` reverts without SC agreement and approveHash() has no false path.
**How found:** Code review of approveHash()/setComplete() signature validation noting approvedHashes can only be set true and never cancelled, combined with reasoning about revert paths (dispute, unallocated funds).
**Exploitation:** A party holding a stale approved hash waits for the original setComplete() to revert (e.g. due to a dispute), then replays the same signature to force task completion at the old terms.
**Insight:** When auditing signature-based approvals, check whether approved hashes can be revoked and whether a reverted execution leaves the signature still valid for replay; look for approve-only setters with no false/cancel path.
