This audit was performed by Carlos (Bloqarl) as an external contractor at Cyfrin, prior to or alongside founding Zealynx Security. It is not a Zealynx engagement, but is included here as part of Carlos’s professional security record.
D2 Finance Vault and Strategy (v2.1)
Cyfrin engagement on D2 Finance, a multi-chain ETF-style vault protocol deployed across Berachain, Arbitrum, Base, and Ethereum. The audit ran from January 10 to February 14, 2025, combining manual review with stateful fuzzing across the vault, strategy, and 12 integration modules covering Aave, Camelot, Dolomite, GMX V2, 1inch, Kodiak, Pendle, Silo, Trader Joe and WETH. The review surfaced 24 findings (2 critical, 2 high, 7 medium, 7 low, 6 informational), including a broken GMX V2 withdrawal path that would have permanently locked user funds, a private key checked into the makefile, an ERC-4626 share-pricing mismatch on cross-chain transfers, and a Berachain reward-claiming interface bug. D2 resolved 19 findings and acknowledged 5. Carlos contributed to this engagement as external contractor at Cyfrin; the testimonial from Dacian on the Zealynx site references this collaboration.
Scope
16 filesFindings
click any row for the full write-upKey Findings
- GMX V2 withdrawal path was non-functional. The strategy registered for the
afterWithdrawalCancellationcallback but never implemented the corresponding interface function. A user-initiated withdrawal would have completed at GMX side, fired the callback into the strategy, and reverted, permanently locking GM token shares and the assets backing them. - Private key was checked into the makefile. The repository shipped with a hardcoded
PRIVATE_KEY(and other secrets) inside the build script, exposing any address derived from that key to anyone with read access to the repo. All affected accounts had to be rotated. - Cross-chain ERC-4626 share transfers leaked value. When a user bridged vault shares through D2OFT to a chain where the vault price-per-share had moved, share burning and minting used the source-chain ratio, causing the receiver to gain or lose value depending on which side had appreciated.
- Berachain reward claiming used the wrong interface.
Bera_Moduleclaimed rewards from Berachain RewardVaults using an interface that did not match the deployed contract, so reward harvesting always reverted on Berachain. - Slippage protection was hardcoded to zero across the Pendle integration. Six entry points in
Pendle_Module(deposit, withdraw, swap, claim, exit) passedminAmountOut = 0, leaving every Pendle trade fully exposed to MEV sandwiching and price manipulation. VaultV3did not validate token transfer success.custodyFunds()andreturnFunds()updatedcustodiedstate and emitted events regardless of whether the underlying ERC-20 transfer succeeded, opening multiple paths to vault state desynchronisation under USDC pause, blacklisting, or false-return tokens.- Wrong Berachain chain ID hardcoded.
Strategy::constructorcheckedblock.chainid == 80000for Berachain instead of the correct80094, meaning the Berachain branch never initialised facets and the strategy was effectively undeployable on Berachain until redeployed.
Team & approval
Disclaimer
This audit is not an endorsement and does not constitute investment advice. Zealynx reviewed the codebase at the commits listed in section 02 over the engagement window. Findings are limited to issues identified within that scope and do not preclude the existence of other vulnerabilities. Subsequent code changes are not covered by this report unless the engagement is explicitly extended.