New Market Trading lost $3.78M after a critical access control flaw let attackers drain 88 Safes across three chains using a preventable bug.

On May 25, 2026, New Market Trading lost $3.78M when an attacker exploited a broken access control check in the protocol's custom Gnosis Safe module, SquidRouterModule. 88 user Safes were drained across Ethereum, Base, and Arbitrum in under 15 minutes.
No flash loan. No phishing. No bridge exploit. The attacker read a public contract, copied a string, encoded a real delegate address from an open on-chain registry, and called a function that had been left unguarded for three months. The vulnerability class, trusting payload data over msg.sender is documented, well-understood, and entirely preventable.
The PermissionsManager contract storing each Safe's registered delegate address was fully public on-chain. The attacker read it directly to enumerate the real delegate per target Safe. No special access required, the keys to the check were sitting in plain sight.
For each target Safe, the attacker crafted a call payload encoding the real delegate address read from PermissionsManager, along with three chained actions: an APPROVE, a PERMIT2 authorization, and a SWAP targeting the relevant attacker-controlled pool. amountOutMin was set to 0 on every swap, no slippage protection needed when you own the pool.

The module verified the caller by checking:
1require(sourceAddress == squidRouter);
2sourceAddress is a parameter the caller supplies themselves. It has no binding to msg.sender or any on-chain identity. The attacker passed the string "squidRouter". Check passed.



The module then ran a permission lookup:
1require(hasPermission(safe, delegate, APPROVE));
2The delegate address fed into this check was decoded from the caller's own payload, not derived from msg.sender. The attacker encoded the real registered delegate. The registry returned a valid result. The check passed. The actual caller was never verified.



The single missing line that stops the entire attack:
1require(msg.sender == delegate);
2With both checks cleared, the module executed all three actions on the victim Safe in sequence: approved the token balance, authorized Permit2, then forced a full-balance swap through the attacker's Uniswap V3 pool. Victims received the worthless "u" token. The attacker held the LP and collected the real assets on the other side of every trade.

After the drain phase, complete, the operator wallet removed liquidity from all pools and collected the real assets. Relay was used to consolidate proceeds cross-chain. Everything was swapped to DAI and swept into a single holding wallet. No direct transfer trail between victim and attacker. The protocol's own swap logic did the moving.



The root cause is a confused deputy vulnerability in SquidRouterModule. The module inherited expressExecuteWithToken() from Axelar's gateway interface, built for relayers, not for vault execution, and placed no additional access control behind it.

Two checks guarded the execution path. The first, sourceAddress == squidRouter, was a caller-supplied string with no cryptographic binding. The second, hasPermission(safe, delegate, APPROVE), ran a real registry lookup but sourced the delegate address from the caller's own payload rather than from msg.sender. An attacker who knew the real delegate, public data, readable by anyone, passed both checks trivially.


The contract verified that a valid delegate exists. It never verified that the caller is that delegate. The vulnerability is not a novel class. It is a documented confused deputy pattern. An audit would have caught it on the first pass.

A security review of SquidRouterModule before V2 deployment would have caught the confused deputy flaw immediately. Any function executing privileged Safe actions must bind caller identity to msg.sender not to a value the caller supplies. The absence of require(msg.sender == delegate) is a critical access control failure that sits at the top of any structured audit checklist.
A review would also have flagged the misuse of expressExecuteWithToken(). The function skips gateway validation by design that is appropriate for bridge relayers, not for executing arbitrary actions on user wallets. Using it as a vault execution entry point without additional gatekeeping is a category error that a threat model surfaces before a line of code hits mainnet.
The attacker did not transfer tokens directly. Each victim Safe was forced to swap its full balance through an attacker-controlled Uniswap V3 pool into the worthless "u" token. Victims received junk. The attacker, as sole LP, collected the real assets from every trade.
After the drain, the operator removed liquidity from all pools, used Relay for cross-chain consolidation, and swept everything to the holding wallet as DAI.

NMT reached out to the attacker via two on-chain messages offering a white-hat bounty, return 80% of drained funds.


Vulnerable Contract (Ethereum / Base / Arbitrum): 0x1f1d37a3Bf840e35c6a860c7C2dA71Fe555123ca
Attacker EOAs:
0x7c82cb4b2909c50c7c0f2b696eee7565e0a23bb80x9bdc730183821b6bb2b51be30b77c964fa645b910xa447f71782135ab96a71374271a749ff7aa54859Attack Contracts:
0xe1d5fcfbba4d46f4937de369de415dd7e2d3265a0x2d450322e3526f489afcc8c49923b35d355c70bcFake Token "u": 0xe6Ff0FE017D09D690493deC0F0f55E8f9Cdc3512
Sample Attack Transaction: 0x59d17fd31e31959b2d562508bf91c4fc1271682ba7d61a6209865e1151b69aea
Bounty Offer Transaction: 0xa6a2f41076ff55d090a197e6d27f5188eea7ac7511b96b66387e9589256df0b3
PermissionManager: 0x03B8B1bA6B02b8A566cB757DFa627f7198c44cB7
One missing require check made 88 user Safes drainable by anyone who read the source code. NMT's V2 module inherited a relayer function never designed for vault execution and sat exposed for three months. The confused deputy pattern is not novel, it has drained protocols before this one. An audit catches it. A threat model anticipates it. Neither was applied to the component that failed.
Contents


From day-zero risk mapping to exchange-ready audits — QuillAudits helps projects grow with confidence. Smart contracts, dApps, infrastructure, compliance — secured end-to-end.