Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 295b00d

Browse files
committed
Don't double hash in smart wallet isValidSignature replay protection
1 parent effd208 commit 295b00d

File tree

3 files changed

+22
-16
lines changed

3 files changed

+22
-16
lines changed

contracts/prebuilts/account/non-upgradeable/Account.sol

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,13 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115
6464

6565
/// @notice See EIP-1271
6666
function isValidSignature(
67-
bytes32 _message,
67+
bytes32 _originalMessageHash,
6868
bytes memory _signature
6969
) public view virtual override returns (bytes4 magicValue) {
70-
bytes32 messageHash = getMessageHash(abi.encode(_message));
71-
address signer = messageHash.recover(_signature);
70+
bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _originalMessageHash));
71+
bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash));
72+
73+
address signer = targetDigest.recover(_signature);
7274

7375
if (isAdmin(signer)) {
7476
return MAGICVALUE;
@@ -89,12 +91,13 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115
8991

9092
/**
9193
* @notice Returns the hash of message that should be signed for EIP1271 verification.
92-
* @param message Message to be hashed i.e. `keccak256(abi.encode(data))`
94+
* @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)`
9395
* @return Hashed message
9496
*/
95-
function getMessageHash(bytes memory message) public view returns (bytes32) {
96-
bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message)));
97-
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), messageHash));
97+
function getMessageHash(bytes memory _message) public view returns (bytes32) {
98+
bytes32 messageHash = keccak256(_message);
99+
bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash));
100+
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash));
98101
}
99102

100103
/*///////////////////////////////////////////////////////////////

contracts/prebuilts/account/utils/AccountExtension.sol

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7
6666

6767
/// @notice See EIP-1271
6868
function isValidSignature(
69-
bytes32 _message,
69+
bytes32 _originalMessageHash,
7070
bytes memory _signature
7171
) public view virtual override returns (bytes4 magicValue) {
72-
bytes32 messageHash = getMessageHash(abi.encode(_message));
73-
address signer = messageHash.recover(_signature);
72+
bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, _originalMessageHash));
73+
bytes32 targetDigest = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash));
74+
75+
address signer = targetDigest.recover(_signature);
7476

7577
if (isAdmin(signer)) {
7678
return MAGICVALUE;
@@ -91,12 +93,13 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7
9193

9294
/**
9395
* @notice Returns the hash of message that should be signed for EIP1271 verification.
94-
* @param message Message to be hashed i.e. `keccak256(abi.encode(data))`
96+
* @param _message The raw abi encoded data to hash and sign i.e. `abi.encode(data)`
9597
* @return Hashed message
9698
*/
97-
function getMessageHash(bytes memory message) public view returns (bytes32) {
98-
bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message)));
99-
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), messageHash));
99+
function getMessageHash(bytes memory _message) public view returns (bytes32) {
100+
bytes32 messageHash = keccak256(_message);
101+
bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash));
102+
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash));
100103
}
101104

102105
/*///////////////////////////////////////////////////////////////

src/test/smart-wallet/AccountVulnPOC.t.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ contract SimpleAccountVulnPOCTest is BaseTest {
278278

279279
// However they can bypass this by using signature verification on number contract instead
280280
vm.prank(accountSigner);
281-
bytes32 digest = keccak256(abi.encode(42));
282-
bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(abi.encode(digest));
281+
bytes memory data = abi.encode(42);
282+
bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(data);
283283
(uint8 v, bytes32 r, bytes32 s) = vm.sign(accountSignerPKey, toSign);
284284
bytes memory signature = abi.encodePacked(r, s, v);
285285

0 commit comments

Comments
 (0)