# return value of 0 from ecrecover not checked

Swivel's validOrderHash compares o.maker to ecrecover output without checking for address(0), so invalid signatures pass when maker is 0x00.

- Payout: Audit contest
- Severity: high
- Program: Swivel
- Found by: gpersoon
- Disclosed: 2021-11-05
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-09-swivel-findings/issues/61
- Library page: https://bugbountylibrary.com/r/c4%3A2021-09-swivel%3AH-04
- Tags: area:web3 domain:web3 impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:auth-bypass vuln:signature-replay

**Target:** Solidity order signature verification (Sig.recover / validOrderHash)
**Root cause:** ecrecover returns address(0) on invalid input, and validOrderHash only requires o.maker == Sig.recover(...) without rejecting a zero result, so a zero maker matches a failed recovery.
**Steps:**
1. Craft an order with `o.maker = address(0)`
2. Supply invalid signature components `c.v`, `c.r`, `c.s` so `ecrecover` returns 0
3. Call the order path; `require(o.maker == Sig.recover(...))` passes since 0 == 0
4. Invalid signature is accepted as valid
**How found:** Code review of signature verification: noticed ecrecover's documented zero-on-error return was not checked, then observed the equality comparison against a caller-controlled o.maker.
**Exploitation:** Submit orders with maker set to 0x00 and malformed signature params so ecrecover errors to zero, bypassing the 'invalid signature' check; practical impact limited because actions require approvals from o.maker.
**Insight:** Whenever a signature check is `require(recovered == claimedSigner)`, test whether the claimed signer can be address(0) and whether ecrecover's error path returns 0 — the two zeros match and the check silently passes.

## Proof of concept (copied exactly from the original report)

**validOrderHash compares maker to ecrecover result**

```
function validOrderHash(Hash.Order calldata o, Sig.Components calldata c) internal view returns (bytes32) {
  ...
  require(o.maker == Sig.recover(Hash.message(domain, hash), c), 'invalid signature');
```

**Sig.recover returns unchecked ecrecover result**

```
function recover(bytes32 h, Components calldata c) internal pure returns (address) {
  ...
  return ecrecover(h, c.v, c.r, c.s);
```

