# Signers can brick safe by adding unlimited additional signers while avoiding checks

HatsSignerGate signers can add owners via execTransaction bypassing maxSigners checks, pushing valid signer count over the immutable cap and bricking the safe.

- Payout: Contest reward
- Severity: high
- Program: Hats
- Credited: Dug
- Disclosed: 2023-02-15
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-02-hats-judging/issues/48
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-hats%3AH-4
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:access-control vuln:business-logic vuln:dos

**Target:** HatsSignerGateBase Solidity contract (Safe module)
**Root cause:** checkAfterExecution only validates threshold, not owner count; owners added via execTransaction bypass claimSigner's maxSigners check, and reconcileSignerCount reverts once validSignerCount > maxSigners.
**Steps:**
1. Signers call `execTransaction` on the Safe to `addOwnerWithThreshold(newOwner, threshold)`
2. Ensure Safe threshold already equals targetThreshold (or new owners are toggled off/ineligible) so `_getCorrectThreshold()` check passes
3. New owners become valid signers (e.g. wearing immutable hats)
4. Subsequent transactions call `checkTransaction` -> `reconcileSignerCount`, which reverts with `MaxSignersReached()` when `validSignerCount > maxSigners`
5. Safe is permanently unusable; funds trapped until hat wearers renounce
**How found:** Code review of checkAfterExecution and reconcileSignerCount: noticed claimSigner enforces maxSigners but execTransaction path does not, and threshold check can be satisfied while owner count grows unbounded.
**Exploitation:** Colluding signers add owners wearing immutable hats while threshold is at targetThreshold, bypassing the threshold check; the immutable maxSigners cap is then exceeded, causing every future transaction to revert and holding the protocol's funds hostage.
**Insight:** When a module enforces invariants in one entrypoint (claimSigner) but the underlying Safe can mutate owners via execTransaction, check post-execution state diffs (full owner array) rather than derived values like threshold.
