Coinbase Smart Wallet - Bigsam's results

Smart Wallet from Coinbase Wallet

General Information

Platform: Code4rena

Start Date: 14/03/2024

Pot Size: $49,000 USDC

Total HM: 3

Participants: 51

Period: 7 days

Judge: 3docSec

Id: 350

League: ETH

Coinbase

Findings Distribution

Researcher Performance

Rank: 30/51

Findings: 1

Award: $36.34

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Awards

36.3397 USDC - $36.34

Labels

bug
disagree with severity
downgraded by judge
grade-a
high quality report
primary issue
QA (Quality Assurance)
sponsor acknowledged
Q-17

External Links

Lines of code

https://github.com/code-423n4/2024-03-coinbase/blob/e0573369b865d47fed778de00a7b6df65ab1744e/src/SmartWallet/CoinbaseSmartWalletFactory.sol#L28-L56

Vulnerability details

Impact

The same address list should give the same address based on the assumption that if the parameters passed are the same but the create account in the factory will deploy 2 different address if the same address are passed when the position of the address are switched with the same nonce. This error will break the already established fact that the same owners list and nonce should give the same address and revert without creating another account. But will not follow this assertion hence invalidating it. The impact of this issue is critical as it undermines the expected behavior of the system regarding account creation. Specifically, it disrupts the deterministic nature of account address generation, potentially leading to confusion, data inconsistencies, and security concerns. If left unaddressed, this issue could compromise the integrity and reliability of the system.

Proof of Concept

The vulnerability can be demonstrated through the following test scenario:

  1. Alice creates an owner list containing two addresses: Address 1 and Address 2, passing Address 1 before Address 2, and creates an account.
  2. Alice removes the list and passes the same addresses, but this time with Address 2 before Address 1, resulting in the creation of another account with a different address for Alice.

The provided test scenario confirms that the system behaves inconsistently when the order of addresses in the owner list is changed, leading to the creation of multiple accounts for the same owner.

function setUp() public {
    account = new CoinbaseSmartWallet();
    factory = new CoinbaseSmartWalletFactory(address(account));
    owners.push(abi.encode(address(1)));
    owners.push(abi.encode(address(2)));
}
  function test_createAccountDeploysToPredeterminedAddress() public {
        address p = factory.getAddress(owners, 0);
        CoinbaseSmartWallet a = factory.createAccount{value: 1e18}(owners, 0);
        assertEq(address(a), p);

        owners.pop();
  owners.pop();
  owners.push(abi.encode(address(2)));
  owners.push(abi.encode(address(1)));
  

 address pp = factory.getAddress(owners, 0);
 CoinbaseSmartWallet aa = factory.createAccount{value: 1e18}(owners,0);
 assertEq(address(aa), pp);

 assertEq(address(aa), address(a));

1 gives 0x761f8B0050e1C64663cdf67b163e139e74f2DDAd::isOwnerAddress;

2 gives0x00b70D9C493558d6F201966236B643EE44a43f30::isOwnerAddress;

Ran 1 test for test/SmartWallet/CoinbaseSmartWalletFactory.t.sol:CoinbaseSmartWalletFactoryTest
[FAIL. Reason: assertion failed] test_createAccountDeploysToPredeterminedAddress() (gas: 545531)
Logs:
  Error: a == b not satisfied [address]
        Left: 0x00b70D9C493558d6F201966236B643EE44a43f30
       Right: 0x761f8B0050e1C64663cdf67b163e139e74f2DDAd

Traces:
  [545531] CoinbaseSmartWalletFactoryTest::test_createAccountDeploysToPredeterminedAddress()
    β”œβ”€ [1979] CoinbaseSmartWalletFactory::getAddress([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002], 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77]) [staticcall]
    β”‚   └─ ← 0x761f8B0050e1C64663cdf67b163e139e74f2DDAd
    β”œβ”€ [241054] CoinbaseSmartWalletFactory::createAccount{value: 1000000000000000000}([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002], 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])    
    β”‚   β”œβ”€ [34337] β†’ new <unknown>@0x761f8B0050e1C64663cdf67b163e139e74f2DDAd
    β”‚   β”‚   └─ ← 95 bytes of code
    β”‚   β”œβ”€ [168692] 0x761f8B0050e1C64663cdf67b163e139e74f2DDAd::initialize([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002])
    β”‚   β”‚   β”œβ”€ [165886] CoinbaseSmartWallet::initialize([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002]) [delegatecall]
    β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 0, owner: 0x0000000000000000000000000000000000000000000000000000000000000001)
    β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 1, owner: 0x0000000000000000000000000000000000000000000000000000000000000002)
    β”‚   β”‚   β”‚   └─ ← ()
    β”‚   β”‚   └─ ← ()
    β”‚   └─ ← 0x761f8B0050e1C64663cdf67b163e139e74f2DDAd
    β”œβ”€ [1979] CoinbaseSmartWalletFactory::getAddress([0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001], 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77]) [staticcall]
    β”‚   └─ ← 0x00b70D9C493558d6F201966236B643EE44a43f30
    β”œβ”€ [238554] CoinbaseSmartWalletFactory::createAccount{value: 1000000000000000000}([0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001], 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])    
    β”‚   β”œβ”€ [34337] β†’ new <unknown>@0x00b70D9C493558d6F201966236B643EE44a43f30
    β”‚   β”‚   └─ ← 95 bytes of code
    β”‚   β”œβ”€ [166192] 0x00b70D9C493558d6F201966236B643EE44a43f30::initialize([0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001])
    β”‚   β”‚   β”œβ”€ [165886] CoinbaseSmartWallet::initialize([0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001]) [delegatecall]
    β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 0, owner: 0x0000000000000000000000000000000000000000000000000000000000000002)
    β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 1, owner: 0x0000000000000000000000000000000000000000000000000000000000000001)
    β”‚   β”‚   β”‚   └─ ← ()
    β”‚   β”‚   └─ ← ()
    β”‚   └─ ← 0x00b70D9C493558d6F201966236B643EE44a43f30
    β”œβ”€ emit log(val: "Error: a == b not satisfied [address]")
    β”œβ”€ emit log_named_address(key: "      Left", val: 0x00b70D9C493558d6F201966236B643EE44a43f30)
    β”œβ”€ emit log_named_address(key: "     Right", val: 0x761f8B0050e1C64663cdf67b163e139e74f2DDAd)
    β”œβ”€ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
    β”‚   └─ ← ()
    └─ ← ()

Test result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 2.07ms

Ran 1 test suite in 2.07ms: 0 tests passed, 1 failed, 0 skipped (1 total tests)

Failing tests:
Encountered 1 failing test in test/SmartWallet/CoinbaseSmartWalletFactory.t.sol:CoinbaseSmartWalletFactoryTest
[FAIL. Reason: assertion failed] test_createAccountDeploysToPredeterminedAddress() (gas: 545531)

when the list of owner was enlogated the system upholds this assertion

function setUp() public {
       account = new CoinbaseSmartWallet();
       factory = new CoinbaseSmartWalletFactory(address(account));
       owners.push(abi.encode(address(1)));
       owners.push(abi.encode(address(2)));
        owners.push(abi.encode(address(3)));
        owners.push(abi.encode(address(4)));
   }
  function test_createAccountDeploysToPredeterminedAddress() public {
       address p = factory.getAddress(owners, 0);
       CoinbaseSmartWallet a = factory.createAccount{value: 1e18}(owners, 0);
       assertEq(address(a), p);

       owners.pop();
 owners.pop();
 owners.push(abi.encode(address(2)));
 owners.push(abi.encode(address(1)));
 owners.push(abi.encode(address(3)));
 owners.push(abi.encode(address(4)));
 

address pp = factory.getAddress(owners, 0);
CoinbaseSmartWallet aa = factory.createAccount{value: 1e18}(owners,0);
assertEq(address(aa), pp);

assertEq(address(aa), address(a));

Ran 1 test for test/SmartWallet/CoinbaseSmartWalletFactory.t.sol:CoinbaseSmartWalletFactoryTest
[FAIL. Reason: AlreadyOwner(0x0000000000000000000000000000000000000000000000000000000000000002)] test_createAccountDeploysToPredeterminedAddress() (gas: 801156)
Traces:
 [792756] CoinbaseSmartWalletFactoryTest::test_createAccountDeploysToPredeterminedAddress()
   β”œβ”€ [2755] CoinbaseSmartWalletFactory::getAddress([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004], 0) [staticcall]
   β”‚   └─ ← 0xcd6C85B8890C999EE10eF30e9ce0aC831A7B6E58
   β”œβ”€ [385457] CoinbaseSmartWalletFactory::createAccount{value: 1000000000000000000}([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004], 0)
   β”‚   β”œβ”€ [34337] β†’ new <unknown>@0xcd6C85B8890C999EE10eF30e9ce0aC831A7B6E58
   β”‚   β”‚   └─ ← 95 bytes of code
   β”‚   β”œβ”€ [311578] 0xcd6C85B8890C999EE10eF30e9ce0aC831A7B6E58::initialize([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004])
   β”‚   β”‚   β”œβ”€ [308736] CoinbaseSmartWallet::initialize([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004]) [delegatecall]
   β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 0, owner: 0x0000000000000000000000000000000000000000000000000000000000000001)
   β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 1, owner: 0x0000000000000000000000000000000000000000000000000000000000000002)
   β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 2, owner: 0x0000000000000000000000000000000000000000000000000000000000000003)
   β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 3, owner: 0x0000000000000000000000000000000000000000000000000000000000000004)
   β”‚   β”‚   β”‚   └─ ← ()
   β”‚   β”‚   └─ ← ()
   β”‚   └─ ← 0xcd6C85B8890C999EE10eF30e9ce0aC831A7B6E58
   β”œβ”€ [3532] CoinbaseSmartWalletFactory::getAddress([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004], 0) [staticcall]
   β”‚   └─ ← 0x5f01e364aA7bca426802DD1ac2275371Dc84eaE9
   β”œβ”€ [245225] CoinbaseSmartWalletFactory::createAccount{value: 1000000000000000000}([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004], 0)
   β”‚   β”œβ”€ [34337] β†’ new <unknown>@0x5f01e364aA7bca426802DD1ac2275371Dc84eaE9
   β”‚   β”‚   └─ ← 95 bytes of code
   β”‚   β”œβ”€ [169896] 0x5f01e364aA7bca426802DD1ac2275371Dc84eaE9::initialize([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004])
   β”‚   β”‚   β”œβ”€ [169507] CoinbaseSmartWallet::initialize([0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000000000000000000000000000004]) [delegatecall]
   β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 0, owner: 0x0000000000000000000000000000000000000000000000000000000000000001)
   β”‚   β”‚   β”‚   β”œβ”€ emit AddOwner(index: 1, owner: 0x0000000000000000000000000000000000000000000000000000000000000002)
   β”‚   β”‚   β”‚   └─ ← AlreadyOwner(0x0000000000000000000000000000000000000000000000000000000000000002)
   β”‚   β”‚   └─ ← AlreadyOwner(0x0000000000000000000000000000000000000000000000000000000000000002)
   β”‚   └─ ← AlreadyOwner(0x0000000000000000000000000000000000000000000000000000000000000002)
   └─ ← AlreadyOwner(0x0000000000000000000000000000000000000000000000000000000000000002)

Test result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 5.00ms

Ran 1 test suite in 5.00ms: 0 tests passed, 1 failed, 0 skipped (1 total tests)

Failing tests:
Encountered 1 failing test in test/SmartWallet/CoinbaseSmartWalletFactory.t.sol:CoinbaseSmartWalletFactoryTest
[FAIL. Reason: AlreadyOwner(0x0000000000000000000000000000000000000000000000000000000000000002)] test_createAccountDeploysToPredeterminedAddress() (gas: 801156)

Encountered a total of 1 failing tests, 0 tests succeeded

Tools Used

The vulnerability was identified through manual testing and analysis, utilizing custom test scripts and the Foundry testing framework.

The protocol should consider reverting the create wallet function when the number of owners is 2 or should review this function to ensure that the same addresses will not deploy different account with the same nonce

Assessed type

Error

#0 - c4-pre-sort

2024-03-22T06:01:58Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2024-03-22T06:03:04Z

raymondfam marked the issue as high quality report

#2 - raymondfam

2024-03-22T06:03:29Z

This would indeed be an issue and extend beyond securing SCW deployment on various chains for the same address.

#3 - c4-pre-sort

2024-03-22T06:04:21Z

raymondfam marked the issue as duplicate of #46

#4 - c4-pre-sort

2024-03-22T23:17:30Z

raymondfam marked the issue as not a duplicate

#5 - c4-pre-sort

2024-03-22T23:17:35Z

raymondfam marked the issue as primary issue

#6 - wilsoncusack

2024-03-26T12:41:41Z

This is working as intended. Users need to pass original owners in the same order to get the same address.

#7 - c4-sponsor

2024-03-26T15:01:21Z

wilsoncusack marked the issue as disagree with severity

#8 - c4-sponsor

2024-03-26T15:01:24Z

wilsoncusack (sponsor) acknowledged

#9 - 3docSec

2024-03-27T04:47:18Z

User mistake with no impact other than purely UX - having to recreate the wallet with a different input order.

#10 - c4-judge

2024-03-27T04:47:45Z

3docSec changed the severity to QA (Quality Assurance)

#11 - c4-judge

2024-03-27T04:47:55Z

3docSec marked the issue as grade-a

#12 - c4-judge

2024-03-27T05:40:28Z

This previously downgraded issue has been upgraded by 3docSec

#13 - 3docSec

2024-03-27T05:40:51Z

(temporarily upgrading to to dedupe #114)

#14 - c4-judge

2024-03-27T05:41:42Z

3docSec changed the severity to QA (Quality Assurance)

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter