Headline
CVE-2023-40014: Adjust ERC2771Context._msgData for msg.data.length < 20 (#4484) · OpenZeppelin/openzeppelin-contracts@9445f96
OpenZeppelin Contracts is a library for secure smart contract development. Starting in version 4.0.0 and prior to version 4.9.3, contracts using ERC2771Context
along with a custom trusted forwarder may see _msgSender
return address(0)
in calls that originate from the forwarder with calldata shorter than 20 bytes. This combination of circumstances does not appear to be common, in particular it is not the case for MinimalForwarder
from OpenZeppelin Contracts, or any deployed forwarder the team is aware of, given that the signer address is appended to all calls that originate from these forwarders. The problem has been patched in v4.9.3.
Expand Up
@@ -12,7 +12,7 @@ const ContextMockCaller = artifacts.require(‘ContextMockCaller’);
const { shouldBehaveLikeRegularContext } = require(‘…/utils/Context.behavior’);
contract('ERC2771Context’, function (accounts) {
const [, anotherAccount] = accounts;
const [, trustedForwarder] = accounts;
const MAX_UINT48 = web3.utils.toBN(1).shln(48).subn(1).toString();
Expand Down Expand Up
@@ -84,11 +84,11 @@ contract('ERC2771Context’, function (accounts) {
it('returns the original sender when calldata length is less than 20 bytes (address length)', async function () {
// The forwarder doesn’t produce calls with calldata length less than 20 bytes
const recipient = await ERC2771ContextMock.new(anotherAccount);
const recipient = await ERC2771ContextMock.new(trustedForwarder);
const { receipt } = await recipient.msgSender({ from: anotherAccount });
const { receipt } = await recipient.msgSender({ from: trustedForwarder });
await expectEvent(receipt, 'Sender’, { sender: anotherAccount });
await expectEvent(receipt, 'Sender’, { sender: trustedForwarder });
});
});
Expand Down Expand Up
@@ -117,5 +117,15 @@ contract('ERC2771Context’, function (accounts) {
await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data’, { data, integerValue, stringValue });
});
});
it('returns the full original data when calldata length is less than 20 bytes (address length)', async function () {
// The forwarder doesn’t produce calls with calldata length less than 20 bytes
const recipient = await ERC2771ContextMock.new(trustedForwarder);
const { receipt } = await recipient.msgDataShort({ from: trustedForwarder });
const data = recipient.contract.methods.msgDataShort().encodeABI();
await expectEvent(receipt, 'DataShort’, { data });
});
});
});
Related news
### Impact OpenZeppelin Contracts is a library for secure smart contract development. Starting in version 4.0.0 and prior to version 4.9.3, contracts using `ERC2771Context` along with a custom trusted forwarder may see `_msgSender` return `address(0)` in calls that originate from the forwarder with calldata shorter than 20 bytes. This combination of circumstances does not appear to be common, in particular it is not the case for `MinimalForwarder` from OpenZeppelin Contracts, or any deployed forwarder the team is aware of, given that the signer address is appended to all calls that originate from these forwarders. ### Patches The problem has been patched in v4.9.3.