When Signing Is Not Secure
GiddyDefi Exploit
On April 23, 2026, GiddyDefi’s GiddyVaultV3 contracts on Ethereum were exploited for an estimated loss of approximately $1.3M. The bug was not a flashloan trick or a price manipulation. It was an authorization bug: the vault accepted a backend signature over only part of the swap data, while the unsigned fields still controlled token approvals, call targets, token movement, and balance checks.
Overview
Attacker: 0x81Fe3D7d35dFeFa15b9E6800B6aeFC3358E7b156
Vulnerable Implementation: 0x5f0ad32c00641d1d2bb628ff341e0d4bb4494318
Exploit TX: 0x5edb66a4c2ea55bba95d36d27713e3bb1c67c3c4199a8a1759e754c6f25482e5
Exploit Analysis
GiddyVaultV3 uses a signed authorization struct called VaultAuth. Every deposit, withdraw, and compound operation validates this authorization before executing.
The swap objects are not just metadata. They decide which token is moved, how much is approved, which contract receives the approval, and which contract is called.
The problem is that the EIP-712 hash does not cover the full SwapInfo.
The Signed Message
The declared type hash only includes nonce, deadline, top-level amount, and bytes[] data.
Inside _validateAuthorization, the contract loops over the swap arrays and hashes only each swap’s data field.
The following fields are present in calldata but are not signed:
swap.fromToken
swap.toToken
swap.amount
swap.aggregator
That is the core bug.
The nonce check means this should not be described as a simple replay of an already-used signature. A successful authorization burns its nonce; the same validation path reverts when nonceUsed[auth.nonce] is already true and later marks the nonce as used.
The more precise description is: the attacker submitted a valid authorization, but rebound the unsigned swap wrapper fields to attacker-controlled values. The contract accepted the signature because the signed digest still matched.
Why the Unsigned Fields Were Dangerous
The dangerous part is in GiddyLibraryV3.executeSwap().
These four unsigned fields control real effects:
fromToken controls which token the vault or strategy approves.
amount controls how much allowance is granted.
aggregator controls the spender and external call target.
toToken controls which token balance is checked after the call.
So the signature covered only swap.data, while the unsigned wrapper decided the approval and external call environment around that data.
This is like signing the inside of an envelope while letting the transaction sender rewrite the destination address, the asset, and the amount on the outside.
Attack Flow
The exploit transaction created the attacker contract and used it to interact with multiple Giddy vaults in one transaction.
At a high level:
The attacker submitted a VaultAuth that passed _validateAuthorization().
The attacker kept the signed data hash valid but changed unsigned SwapInfo fields.
fromToken was set to real gauge tokens held by the strategy.
aggregator was set to attacker-controlled 0x7326...4528.
executeSwap() called forceApprove(fromToken, aggregator, amount).
The malicious aggregator used that allowance path to move the approved gauge tokens.
The fake toToken behavior satisfied the vault’s post-swap received-token check.
The Root Cause
The root cause was incomplete signature coverage.
The contract treated SwapInfo.data as if it represented the whole swap. It did not. The actual swap identity was fromToken + toToken + amount + aggregator + data, and only one component of that tuple was signed.
Because aggregator was unsigned, the attacker could choose the call target. Because fromToken and amount were unsigned, the attacker could choose the token allowance. Because toToken was unsigned, the attacker could satisfy the output check with a fake or attacker-controlled token.
The post-call checks were not enough:
These checks only prove that the selected fromToken balance decreased and the selected toToken balance increased. If the attacker can select both tokens and the aggregator, those checks are no longer meaningful security boundaries.
Conclusion
When using off-chain signatures to authorize on-chain execution, always proceed with caution. EIP-712 only protects the fields included in the signed digest. Any field left unsigned should be treated as user-controlled, because it can be altered in calldata and may become part of the exploit path.
Furthermore, conducting a security audit is strongly recommended for all projects, even though they are smart contracts, backends, wallets, or dapps.






