Category: Business Logic
Missing access control on postRelayedCall
leading to ETH transfer from Vault
High Severity
Medium Impact
High Likelihood
Description
The VoyagePaymaster::postRelayedCall
function is lacking any access control check. The function invokes refundGas
on a vault supplied by the caller to refund a caller controlled amount of ETH to the treasury address.
function postRelayedCall(
bytes calldata context,
bool success,
uint256 gasUseWithoutPost,
GsnTypes.RelayData calldata relayData
) external virtual override {
address vault = abi.decode(context, (address));
// calldata overhead = 21k + non_zero_bytes * 16 + zero_bytes * 4
// ~= 21k + calldata.length * [1/3 * 16 + 2/3 * 4]
uint256 minimumFees = (gasUseWithoutPost +
21000 +
msg.data.length *
8 +
REFUND_GAS_OVERHEAD) * relayData.gasPrice;
uint256 refund = vault.balance >= minimumFees
? minimumFees
: minimumFees + 21000 * relayData.gasPrice; // cover cost of unwrapping WETH
IVault(vault).refundGas(refund, treasury);
}
Impact
A malicious user can invoke postRelayedCall
to transfer ETH from any vault to the treasury address.
Recommendations
Apply strict access control to the function.
Remediation
Commit 791b7e63↗ was indicated as containing the remediation. The commit correctly fixes the issue by enforcing access control to postRelayedCall
.