# Missing access control on UTB:receiveFromBridge allows UTB swaps to be executed without spending bridge fees while bypassing fee/swap instruction signature verification

Public UTB.receiveFromBridge lacks access control, letting anyone call _swapAndExecute directly to skip bridge fees and validator signature checks on swap instructions.

- Payout: Contest reward
- Severity: medium
- Program: Decent
- Credited: GhK3Ndf
- Disclosed: 2024-03-22
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2024-01-decent-findings/issues/590
- Library page: https://bugbountylibrary.com/r/c4%3A2024-01-decent%3AM-03
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic vuln:fee-bypass vuln:signature-replay

**Target:** UTB.sol receiveFromBridge / _swapAndExecute on EVM
**Root cause:** receiveFromBridge is public with no access control and calls _swapAndExecute directly, skipping the retrieveAndCollectFees modifier that collects fees and validates fee/swap instruction signatures via UTBFeeCollector.collectFees.
**Steps:**
1. Deploy UTB + swapper + feeCollector on source chain; set feeCollector so swapAndExecute enforces fees/signature.
2. Build SwapAndExecuteInstructions (swap WETH->USDC, target=cat, payload=abi.encodeCall(cat.mintWithUsdc,(bob))).
3. Call `src_utb.receiveFromBridge(_instructions.swapInstructions, _instructions.target, _instructions.paymentOperator, _instructions.payload, _instructions.refund)` directly, no fees/signature.
4. Observe alice ETH balance unchanged, feeCollector balance 0, yet swap executes and NFT minted.
5. For arbitrary calldata: set swapParams amountOut=0 same token, target=POC contract, payload=abi.encodeCall(ap.called,()) and call receiveFromBridge; POC event fires.
**How found:** Code review of UTB public entrypoints: noticed swapAndExecute/bridgeAndExecute carry retrieveAndCollectFees modifier but receiveFromBridge (intended only for bridge adapters) is public and calls the same private _swapAndExecute, so the fee/signature gate is skipped.
**Exploitation:** Attacker calls the public receiveFromBridge with self-crafted SwapInstructions and payload; _swapAndExecute performs the swap and forwards tokenOut to UTBExecutor.execute, which calls the attacker-chosen target with arbitrary payload, all without paying fees or presenting a validator signature.
**Escalation:** Arbitrary unsigned payload execution via UTBExecutor.execute raises impact beyond fee avoidance to unquantifiable arbitrary-call surface.
**Insight:** When a contract has multiple public entrypoints funneling into one private core function, diff their modifiers: any public path into the core that lacks the fee/signature gate is a bypass. Also check whether 'internal-only' functions intended for adapter callbacks are actually public.
