# onlyCentrifugeChainOrigin() can’t require msg.sender equal axelarGateway

AxelarRouter's onlyCentrifugeChainOrigin modifier required msg.sender==axelarGateway, but the gateway never calls execute(), so cross-chain commands could never run.

- Payout: Audit contest
- Severity: medium
- Program: Centrifuge
- Found by: bin2chen
- Disclosed: 2023-10-11
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2023-09-centrifuge#m-01
- Library page: https://bugbountylibrary.com/r/c4%3A2023-09-centrifuge%3AM-01
- Tags: area:web3 domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity vuln:access-control vuln:business-logic

**Target:** AxelarRouter.sol cross-chain execute() entrypoint
**Root cause:** The modifier required msg.sender == address(axelarGateway), but AxelarGateway never makes external calls to the router's execute(); validation is meant to come from validateContractCall plus sourceChain/sourceAddress checks.
**Steps:**
1. Read onlyCentrifugeChainOrigin() in AxelarRouter.sol: `require(msg.sender == address(axelarGateway), "AxelarRouter/invalid-origin")`
2. Inspect AxelarGateway.sol (axelarnetwork/axelar-cgp-solidity) and confirm no code path calls router.execute()
3. Conclude msg.sender can never equal axelarGateway, so execute() always reverts
4. Fix: remove the msg.sender require, keeping sourceChain/sourceAddress and validateContractCall checks
**How found:** Code review of the modifier against the actual AxelarGateway implementation; noticed the official example does not restrict msg.sender and searched the gateway contract for any call to router.execute(), finding none.
**Insight:** When a contract gates on msg.sender == trustedContract, verify the trusted contract actually calls you; cross-chain gateways typically authenticate via validateContractCall, not by being the caller.

