# expressReceiveToken can be abused using reentry

InterchainTokenService.expressReceiveTokenWithData violates checks-effects-interactions, letting a recipient reenter execute() and receive both the express and cross-chain transfer, stealing the express payer's funds.

- Payout: Contest reward
- Severity: high
- Program: Axelar Network
- Credited: immeas
- Disclosed: 2023-11-29
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2023-07-axelar-findings/issues/349
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-axelar%3AH-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:reentrancy

**Target:** InterchainTokenService.expressReceiveTokenWithData / expressReceiveToken (Solidity contract)
**Root cause:** _setExpressReceiveTokenWithData is called after the external token transfer and the expressExecuteWithInterchainToken callback, so a malicious destination contract can reenter InterchainTokenService.execute with the same commandId before state is recorded.
**Steps:**
1. Deploy a malicious destination contract implementing expressExecuteWithInterchainToken that calls AxelarGateway.execute (or approveContractCall in tests) then InterchainTokenService.execute(commandId, sourceChain, sourceAddress, payload).
2. Attacker initiates a large cross-chain token transfer to the destination contract.
3. Front-run the Axelar gateway execute call by invoking a third-party expressReceiveTokenWithData(tokenId, sourceChain, sourceAddress, recipient, amount, data, commandId).
4. Express payer transfers `amount` to recipient; recipient's expressExecuteWithInterchainToken reenters execute() and triggers the second transfer of `amount` from TokenManager.
5. _setExpressReceiveTokenWithData runs afterward; commandId already executed, recipient holds 2x amount, express payer loses funds.
6. PoC: ExpressRecipient.sol + tokenService.js test asserting token.balanceOf(recipient) == amount*2.
**How found:** Code review of expressReceiveTokenWithData noticing _setExpressReceiveTokenWithData is written after the external safeTransferFrom and the expressExecuteWithInterchainToken callback — a CEI violation enabling reentry into execute() with the same commandId.
**Exploitation:** Attacker front-runs the Axelar gateway execute in the mempool (or an Axelar operator withholds the execute call) and routes the express receive to a malicious destination contract. The contract's expressExecuteWithInterchainToken callback calls gateway.execute then InterchainTokenService.execute for the same commandId, pulling the original cross-chain transfer in addition to the express transfer, netting 2x amount at the express payer's expense.
**Insight:** Express/liquidity-provider paths that pay out before recording the commandId are prime reentrancy targets: check whether the executed-command marker is set before the token transfer and before any user-controlled callback, and whether the same commandId can be replayed through the normal execute path.
