Anyone who is approving BlueprintV5 contract to spend ERC20 can get drained because Payment::payWithERC20
Summary
payWithERC20 is supposed to be used inside BlueprintV5 contract to handle payment. But this function also can be used to drain anyone who is interact with BlueprintV5 and using it to approve payment token when creating an agent.
Root Cause
@> function payWithERC20(address erc20TokenAddress, uint256 amount, address fromAddress, address toAddress) public {
// check from and to address
require(fromAddress != toAddress, "Cannot transfer to self address");
require(toAddress != address(0), "Invalid to address");
require(amount > 0, "Amount must be greater than 0");
IERC20 token = IERC20(erc20TokenAddress);
token.safeTransferFrom(fromAddress, toAddress, amount);
}the root cause simply because this function is public function, meaning anyone can call this and supply valid token address, then fill fromAddress with any address that still have allowance/approving the payment token to be spend by BlueprintV5 contract
Internal Pre-conditions
- admin enable usdc or any erc20 token as payment by calling
Blueprint::addPaymentAddress
External Pre-conditions
- victim approve the spending of usdc or any erc20 token set in last step for
BlueprintV5contract address proxy - the amount approved should be greater than the amount used for creating agent with token cost
- victim call the function to create agent (optional)
Attack Path
- attacker call
payWithERC20supplying the parameter with usdc address, victim address and sufficient amount to be sent into attacker address
Impact
user/victim who interacted would lose their funds drained by attacker
Mitigation
make the Payment::payWithERC20 internal