Reproduced Exploit
YieldFi CCIP: every inbound message reverts when decoded (`uint32` vs `uint64` chain selector)
Chain
Other
Category
untagged
Date
Apr 2025
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 55537-all-ccip-messages-reverts-when-decoded-cyfrin-none-yieldfi-m. Standalone Foundry PoC and full write-up: 55537-all-ccip-messages-reverts-when-decoded-cyfrin-none-yieldfi-m_exp in the
evm-hack-registrymirror.
Protocol: YieldFi (v2.0) · Auditor: Cyfrin (Immeas) · Severity: High
AuditVault: #55537 · Report: Cyfrin YieldFi v2.0
Vulnerable source: contracts/libs/Codec.sol — decodeBridgeSendPayload · driven by contracts/bridge/ccip/BridgeCCIP.sol — _ccipReceive
Fix commit: 14fc17a (dstId changed to uint64)
Provenance#
The audited repo YieldFiLabs/contracts@40caad6c was deleted (no fork, no
mirror, Wayback returns 404). The exploit path here uses only real YieldFi
source recovered from surviving sources:
src/yieldfi/Codec.sol,Constants.sol,Common.sol— byte-identical to the publicYieldFiLabs/smart-contractsrepo (the vulnerableuint32 dstIddecode is present there verbatim; only thedecodeBridgeSendPayloadparameter isbytes memoryto match the audited_ccipReceivecall site).src/yieldfi/BridgeCCIP.sol— thesendand_ccipReceivebodies are reproduced verbatim from the Cyfrin report (the auditor's own copy of the audited source).src/chainlink/*— the real Chainlink CCIP framework (Client,CCIPReceiver,IRouterClient) fromsmartcontractkit/ccip.
Root cause#
BridgeCCIP.send builds the custom payload with the uint64 destination
chain selector as the first field:
bytes memory _encodedMessage =
abi.encode(_dstChain /*uint64*/, _to, tokens[_yToken][_dstChain], _amount, Constants.BRIDGE_SEND_HASH);
On the destination chain, _ccipReceive hands the payload to the real
Codec.decodeBridgeSendPayload, which decodes that first field into a
uint32:
(uint32 dstId, address to, address token, uint256 amount, bytes32 trxnType) =
abi.decode(_data, (uint32, address, address, uint256, bytes32));
Every Chainlink CCIP chain selector is a uint64 far above uint32.max
(Ethereum = 5009297550715157269). abi.decode validates the high bits of the
32-byte word and reverts when they are non-zero. So every inbound CCIP
message reverts on this first statement, before any handling. BridgeCCIP is
not upgradeable and CCIP messages cannot be retried → permanent cross-chain
liveness break; bridged tokens are locked/burned on the source with nothing
released on the destination.
Reproduction#
test/…_exp.sol (registry, [PASS]):
test_everyCcipMessageRevertsOnDecode— a user bridges via the realBridgeCCIP.send(packing theuint64Base selector); a router double relays the exact bytes to the destination bridge; the real_ccipReceivereverts while decoding. The message can never be processed.test_codec_control_uint32_vs_uint64_selector— the same well-formed payload decodes cleanly through the realCodecwhendstIdis withinuint32range, and reverts for the real Ethereum selector — isolating the mechanism as theuint64 → uint32truncation, not a malformed payload.
_shared/run-poc/run_poc.sh 55537-all-ccip-messages-reverts-when-decoded-cyfrin-none-yieldfi-m_exp -vvvvv
Fix#
Change Codec.BridgeSendPayload.dstId (and the abi.decode type) to uint64,
matching the Chainlink chain-selector width (fix commit 14fc17a).
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 55537-all-ccip-messages-reverts-when-decoded-cyfrin-none-yieldfi-m_exp (evm-hack-registry mirror).
- AuditVault finding: 55537-all-ccip-messages-reverts-when-decoded-cyfrin-none-yieldfi-m.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "YieldFi CCIP: every inbound message reverts when decoded (
uint32vsuint64chain selector)". - Web3Sec X hacked database: search.
- Rekt leaderboard: search.
- Solodit incident search: search.
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.