HardhatFoundry
30,000 USDC
View results
Submission Details
Severity: low
Valid

The `indexed` Keyword in Events Causes Data Loss for Variables of type `bytes`

Summary

By making the event topic indexed for bytes type inside the NexusAccountFactory contract, it would lead for wrong variable to be emitted

Vulnerability Details

when the indexed keyword is used for reference type variables such as dynamic arrays or strings, it will return the hash of the mentioned variables.
Thus, the event which is supposed to inform all of the applications subscribed to its emitting transaction (e.g. front-end of the DApp, or the backend listeners to that event),
would get a meaningless and obscure 32 bytes that correspond to keccak256 of an encoded dynamic array. This may cause some problems on the DApp side and even lead to data loss.
For more information about the indexed events, check here:

(https://docs.soliditylang.org/en/v0.8.17/abi-spec.html?highlight=indexed#events)

The problem exists inside the NexusAccountFactory contract. The event AccountCreated is defined in such a way that the bytes variable of initData is indexed.
The function createAccount() is intended to create a new Nexus account with the provided initialization data.
However, with the current design, the expected parameter wouldn't be emitted properly and front-end would get a meaningless one-way hash.

/// @notice Emitted when a new Smart Account is created, capturing the account details and associated module configurations.
event AccountCreated(address indexed account, bytes indexed initData, bytes32 indexed salt);

https://github.com/bcnmy/nexus/blob/main/contracts/interfaces/factory/INexusAccountFactory.sol#L27

Impact

Proof of Concept

Consider this scenario as an example:

  1. The function createAccount() is called

  2. Inside the function createAccount() we expect to see the the bytes of initData from calldata be emitted

  3. But as the event topic is defined as indexed we'll get an obscure 32-byte hash and listeners will not be notified properly. Thus, the initData would be lost in the DApp.

For test purposes, one can run this test file:

event AccountCreated(address indexed account, bytes indexed initData, bytes32 indexed salt);
event AccountCreated1(address indexed account, bytes initData, bytes32 indexed salt);
function test_emitter(bytes calldata initData) public {
bytes32 salt = bytes32(abi.encodePacked(keccak256("N")));
emit AccountCreated(address(this), initData, salt);
emit AccountCreated1(address(this), initData, salt);
}

Outputs of test: (with sample initData equal to 0x9cc7a4860f0b0926603c77f2e17ec5408745d45e2b668a287ed04e3aab0ea3d0)

AccountCreated event:

[
{
"from": "0xa35EEbcac6c93ad12b4dedFB6E651c6eeB252541",
"topic": "0x47e5b5fc3bda028416e26dcf66ca5186488c0717e8ab55bb01806113f1839d58",
"event": "AccountCreated",
"args": {
"0": "0xa35EEbcac6c93ad12b4dedFB6E651c6eeB252541",
"1": {
"_isIndexed": true,
"hash": "0x159308d99255c44d054988b9b6b1c977b00fd95c53a393332fde1842793b5dc8"
},
"2": "0x7c1e3133c5e040bb7fc55cda56e3c1998a2e33373c0850e92b53c932b65ceb44"
}
}

AccountCreated1 event:

{
"from": "0xa35EEbcac6c93ad12b4dedFB6E651c6eeB252541",
"topic": "0x211750db703759f2a69f94ed7881c771170ea46af0ddfc4bdb646b25638e9032",
"event": "AccountCreated1",
"args": {
"0": "0xa35EEbcac6c93ad12b4dedFB6E651c6eeB252541",
"1": "0x9cc7a4860f0b0926603c77f2e17ec5408745d45e2b668a287ed04e3aab0ea3d0",
"2": "0x7c1e3133c5e040bb7fc55cda56e3c1998a2e33373c0850e92b53c932b65ceb44",
"account": "0xa35EEbcac6c93ad12b4dedFB6E651c6eeB252541",
"initData": "0x9cc7a4860f0b0926603c77f2e17ec5408745d45e2b668a287ed04e3aab0ea3d0",
"salt": "0x7c1e3133c5e040bb7fc55cda56e3c1998a2e33373c0850e92b53c932b65ceb44"
}
}
]

As it is clear from the emitted data, the AccountCreated returns the hash of the initData while the AccountCreated1 returns the original bytes variable.

Tools Used

Manual

Recommendations

/// @notice Emitted when a new Smart Account is created, capturing the account details and associated module configurations.
- event AccountCreated(address indexed account, bytes indexed initData, bytes32 indexed salt);
+ event AccountCreated(address indexed account, bytes initData, bytes32 indexed salt);
Updates

Lead Judging Commences

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

finding-wrong-event-emission-indexed

Valid low severity, simply inconsistency in events affecting off-chain indexing

Support

FAQs

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