DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: medium
Invalid

`LibClipboard::decode` function returns wrong result for the `returnPasteParams`

Summary

The LibClipboard::decode function decodes the input parameter clipboard and returns the typeId, etherValue and returnPasteParams. But the returned returnPasteParams is not correct.

Vulnerability Details

The LibClipboard::decode function should decode the input clipboard and return the typeId, etherValue and returnPasteParams:

function decode(
bytes memory clipboard
)
internal
pure
returns (bytes1 typeId, uint256 etherValue, bytes32[] memory returnPasteParams)
{
typeId = clipboard[0];
if (typeId == 0x01) {
returnPasteParams = new bytes32[](1);
@> returnPasteParams[0] = abi.decode(clipboard, (bytes32));
} else if (typeId == 0x02) {
@> (, returnPasteParams) = abi.decode(clipboard, (bytes2, bytes32[]));
}
bytes1 useEther = clipboard[1];
if (useEther == 0x01) {
etherValue = clipboard.toUint256(clipboard.length - 32);
}
}

The LibClipboard::decode function returns incorrect decoding returnPasteParams.
Let's consider the following scenario:
The input parameter clipboard is: 0x0100000000000000000000000000000000000000000000000000000000001234 (the Ether value is 0).
The expectected returnPasteParams is: 0x0000000000000000000000000000000000000000000000000000000000001234.
But the actual return value is: 0x0100000000000000000000000000000000000000000000000000000000001234.

Impact

The LibClipboard::decode function attempts to decode the entire clipboard as a bytes32, which is incorrect. This leads to improper extraction of the returnPasteParams. The returned returnPasteParams includes also typeId and etherValue.
The following test shows that the decode function doesn't decode correctly the returnPasteParams.
To simplify the test a new foundry setup is made with Decode contract that contains the encode and decode functions:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;
contract Decode {
function encode(
uint256 etherValue,
bytes32[] memory returnPasteParams
) public pure returns (bytes memory clipboard) {
uint8 useEther = etherValue == 0 ? 0 : 1;
if (returnPasteParams.length == 0) {
clipboard = abi.encodePacked(uint8(0), useEther);
} else if (returnPasteParams.length == 1) {
clipboard = abi.encodePacked(
uint8(1),
useEther,
uint240(uint256(returnPasteParams[0])) // remove padding
);
} else {
clipboard = abi.encode(
(uint256(0x02) << 248) | (uint256(useEther) << 240), // type + ether
returnPasteParams
);
}
if (useEther == 1) {
clipboard = abi.encodePacked(clipboard, etherValue);
}
return clipboard;
}
function decode(
bytes memory clipboard
)
public
pure
returns (bytes1 typeId, uint256 etherValue, bytes32[] memory returnPasteParams)
{
typeId = clipboard[0];
if (typeId == 0x01) {
returnPasteParams = new bytes32[](1);
returnPasteParams[0] = abi.decode(clipboard, (bytes32));
} else if (typeId == 0x02) {
(, returnPasteParams) = abi.decode(clipboard, (bytes2, bytes32[]));
}
bytes1 useEther = clipboard[1];
if (useEther == 0x01) {
etherValue = toUint256(clipboard, clipboard.length - 32);
}
}
function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
require(_start + 32 >= _start, "toUint256_overflow");
require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
}

And the test file Decode.t.sol with test function testDecode:

function testDecode() public {
bytes32[] memory returnPasteParams = new bytes32[](1);
returnPasteParams[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000001234);
//Use encode function to create the clipboard
bytes memory clipboard = decode.encode(0, returnPasteParams);
(bytes1 typeId, uint256 etherValue, bytes32[] memory returnPasteParams1) = decode.decode(clipboard);
assertEq(returnPasteParams1[0], bytes32(0x0000000000000000000000000000000000000000000000000000000000001234));
}

And the result from the test is:

Ran 1 test for test/DecodeTest.t.sol:DecodeTest
[FAIL. Reason: assertion failed] testDecode() (gas: 28697)
Logs:
Error: a == b not satisfied [bytes32]
Left: 0x0100000000000000000000000000000000000000000000000000000000001234
Right: 0x0000000000000000000000000000000000000000000000000000000000001234

The test shows that the function LibClipboasr::decode doesn't return the correct returnPasteParams.
Several functions rely on the result from the decode function: LibClipboard::useClipboard, Drafter::decodeClipboard, LibFarm::_advancedFarm and LibFarm::_advancedFarmMem. These functions will receive wrong result for the returnPasteParams parameter.

It is also worth noting that there is a mistake in the LibClipboard::encode function too. The following test testEncode shows that the function LibClipboard::encode returns wrong clipboard by large values for returnPasteParams when the length is 1:

function testEncode() public {
bytes32[] memory returnPasteParams = new bytes32[](1);
returnPasteParams[0] = bytes32(0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef);
bytes memory clipboard = decode.encode(0, returnPasteParams);
}

The result is: [Return] 0x0100567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.
But the expected result is: 0x01001234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef. This is because of the removing padding in the line uint240(uint256(returnPasteParams[0])). But I guess that this function will not be used with such a big values so the impact of the mistake in encode function is low. The bigger problem is the issue in the decode function, because it returns by every call wrong result for returnPasteParams parameter and several functions in different contracts rely on this result.

Tools Used

Manual Review, Foundry

Recommendations

Modify the LibClipboard::decode function to slice the clipboard parameter and return only the expected returnPasteParams.

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Clipboard type 0x02 does not decode information propertly and can extract wrong information

Appeal created

inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Clipboard type 0x02 does not decode information propertly and can extract wrong information

Support

FAQs

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