# Signers can bypass checks to add new modules to a safe by abusing reentrancy

HatsSignerGate's module-hash check can be bypassed via reentrancy through Safe multicall, letting signers add malicious modules and gain unlimited control.

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

**Target:** HatsSignerGateBase Zodiac guard on Gnosis Safe
**Root cause:** The reentrancy guard only increments/decrements _guardEntries instead of asserting zero, so a nested execTransaction re-enters checkTransaction and overwrites _existingModulesHash with the post-module-add list, making checkAfterExecution pass.
**Steps:**
1. Signers submit a Safe transaction that snapshots modules into _existingModulesHash in checkTransaction()
2. Transaction uses Safe multicall: first call adds a malicious module via enableModule
3. Second call invokes execTransaction() on the Safe with a benign tx, re-entering checkTransaction()
4. Nested checkTransaction() overwrites _existingModulesHash to include the malicious module
5. Nested checkAfterExecution() passes; outer checkAfterExecution() also passes since hash now matches
6. Malicious module now has unrestricted power over the Safe
**How found:** Noticed the reentrancy guard only relies on underflow protection rather than asserting _guardEntries==0, then reasoned that a nested execTransaction via multicall would re-snapshot the module hash and defeat the post-execution invariant.
**Exploitation:** Threshold-meeting signers bundle enableModule(malicious) plus a self-execTransaction via Safe multicall; the nested call refreshes the module hash snapshot so the post-flight invariant check passes, granting the module unlimited future control.
**Escalation:** New module bypasses all guard checks, equivalent to setting threshold to 1 and removing the guard, giving permanent unrestricted control.
**Insight:** When a guard snapshots state in a pre-check and compares in a post-check, any reentrant path that re-runs the pre-check overwrites the snapshot; verify the guard actually blocks reentry (assert count==0) rather than merely detecting underflow.
