TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: low
Invalid

The use of `abi.encodePacked` to encode the payload and `abi.decode` to decode it can result in incorrect data retrieval

Summary

using abi.encodePacked and then decoded using abi.decode can lead to incorrect decoding, potentially causing the contract to misinterpret the data. As a result, tokens might be minted to unintended addresses, leading to potential loss of funds or tokens being locked up.

Vulnerability Details

Using abi.encodePacked for encoding and then attempting to decode using abi.decode can lead to incorrect decoding. This discrepancy can cause issues, such as minting tokens to incorrect addresses or interpreting the wrong amounts, which can result in loss of funds or locked tokens.
, abi.encodePacked combines the address and amount into a byte array without any delimiters or type information, causing abi.decode to fail or produce incorrect values.
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FTempleTeleporter.sol#L43-L58

function teleport(
uint32 dstEid,
address to,
uint256 amount,
bytes calldata options
) external payable override returns (MessagingReceipt memory receipt) {
if (amount == 0) { revert CommonEventsAndErrors.ExpectedNonZero(); }
if (to == address(0)) { revert CommonEventsAndErrors.InvalidAddress(); }
// Encodes the message before invoking _lzSend.
bytes memory _payload = abi.encodePacked(to.addressToBytes32(), amount);
// debit
temple.burnFrom(msg.sender, amount);
emit TempleTeleported(dstEid, msg.sender, to, amount);
receipt = _lzSend(dstEid, _payload, options, MessagingFee(msg.value, 0), payable(msg.sender));
}

https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FTempleTeleporter.sol#L99-L110

function _lzReceive(
Origin calldata /*_origin*/,
bytes32 /*_guid*/,
bytes calldata _payload,
address /*_executor*/, // Executor address as specified by the OApp.
bytes calldata /*_extraData */ // Any extra data or options to trigger on receipt.
) internal override {
// Decode the payload to get the message
(address _recipient, uint256 _amount) = abi.decode(_payload, (address, uint256));
temple.mint(_recipient, _amount);
}
  1. Encoding with abi.encodePacked:
    This concatenates the address and amount into a single byte array without retaining the type information
    https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FTempleTeleporter.sol#L52

    bytes memory _payload = abi.encodePacked(to.addressToBytes32(), amount);
  2. Decoding with abi.decode:
    Here, abi.decode expects the data to be encoded with abi.encode, which retains type and size information. Since abi.encodePacked does not do this, abi.decode cannot correctly interpret the concatenated data.
    https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FTempleTeleporter.sol#L107

    (address _recipient, uint256 _amount) = abi.decode(_payload, (address, uint256));

The use of abi.encodePacked to encode the payload and abi.decode to decode it can result in incorrect data retrieval, potentially leading to incorrect addresses or amounts being used.
leading to incorrect values for decodedAddress and decodedAmount.

Impact

If the decoding fails or results in wrong values, tokens might be sent to incorrect addresses or not minted at all, leading to a loss of funds. This could lock up tokens, making them irretrievable.

Tools Used

Manual Review

Recommendations

use abi.encode instead of abi.encodePacked for encoding the payload:

function teleport(
uint32 dstEid,
address to,
uint256 amount,
bytes calldata options
) external payable override returns (MessagingReceipt memory receipt) {
if (amount == 0) { revert CommonEventsAndErrors.ExpectedNonZero(); }
if (to == address(0)) { revert CommonEventsAndErrors.InvalidAddress(); }
// Encodes the message before invoking _lzSend.
bytes memory _payload = abi.encode(to, amount);
// debit
temple.burnFrom(msg.sender, amount);
emit TempleTeleported(dstEid, msg.sender, to, amount);
receipt = _lzSend(dstEid, _payload, options, MessagingFee(msg.value, 0), payable(msg.sender));
}
function _lzReceive(
Origin calldata /*_origin*/,
bytes32 /*_guid*/,
bytes calldata _payload,
address /*_executor*/, // Executor address as specified by the OApp.
bytes calldata /*_extraData */ // Any extra data or options to trigger on receipt.
) internal override {
// Decode the payload to get the message
(address _recipient, uint256 _amount) = abi.decode(_payload, (address, uint256));
temple.mint(_recipient, _amount);
}

This ensures that the encoded data retains the type and size information necessary for correct decoding.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

`abi.encodePacked` to encode it while on the recieving it uses `abi.decode()` to decode the payload and it doesn't work like that

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.