Does OpenSea Shared Storefront have a backdoor?

Does OpenSea Shared Storefront have a backdoor?

📅 [ Archival Date ]
Nov 11, 2022 6:20 PM
🏷️ [ Tags ]
NFTOpenSeaWeb3
✍️ [ Author ]

This project demonstrates how OpenSea administrators can take any tokens minted on the OpenSea Shared Storefront. This is a previously-undocumented backdoor.

Is this what artists expected when they decided to mint with OpenSea?

Background

OpenSea Shared Storefront is the ERC-1155 contract deployed on Ethereum Mainnet. If you try to create an NFT using the OpenSea website and follow all the default options without creating your own smart contract, this is where your NFT will go.

At time of writing, this contract holds NFTs “owned” by 600k+ accounts.

There are about 1 million transactions against this contract.

OpenSea administrators maintain control over this contract such that they can take, or freeze, anybody’s NFT at any time. The contract’s source code is not published and this control ability is not disclosed anywhere in OpenSea’s terms of service or documentation.

OpenSea’s level of control should be considered “signature authority” over the assets, for US FinCen purposes and this makes OpenSea administrators capable of executing civil asset seizures/forfeitures requested by governments.

Demonstration

I published a project showing you exactly how to perform these asset seizures.

This project allows you to make a live copy of Ethereum Mainnet, execute some transactions as if you were OpenSea (even though you don’t know their private key) and examine the outcomes.

Setup

  1. Install Yarn.
  2. yarn install

  3. Get access to an Ethereum Mainnet JSON-RPC provider, I recommend Infura.
  4. → https://infura.io

  5. Find some specific NFT for sale inside OpenSea Shared Storefront and get its ID. The demonstration uses46038921131323814396335747090004559834868014221610645288463784344990987059201, change it if you like.
  6. Find the owner of that NFT. The demonstration uses 0xE34228f210354911c0FedAD9941c7Cfd269B9E91, change it if you like or if anybody else receives the NFT from Step 3.

Execute

In one terminal window, execute Hardhat per below. This will allow you to locally try transactions on behalf of OpenSea administrators even though you don't know their private keys.

npx hardhat node --fork https://mainnet.infura.io/v3/xxxxYOURxKEYxxxx

In a second terminal window, execute the demonstration transactions:

node index.mjs

You should see some information printed, the current and new owner for the token and logs for the transfer. This demonstrates that the token was transferred even though the “owner” did not wittingly authorize it..

Example output:

Storefront (ERC-1155): 0x495f947276749ce646f68ac8c248420045cb7b5e
Contract owner:        0xC669B5F25F03be2ac0323037CB57f49eB543657a
Token ID:              46038921131323814396335747090004559834868014221610645288463784344990987059201
Token owner:           0xE34228f210354911c0FedAD9941c7Cfd269B9E91
Proxy registry stub:   0x20348916e39f3fc0E44338745b1bf1d6b57bcdDC
Sender balance:        1
Recipient balance:     0
Transaction hash:      0x70a589322708fba40c9816a089e78cab3628d8c3030e64b9fdee55d07c7cef97
Transaction logs:      [
  {
    transactionIndex: 0,
    blockNumber: 15898730,
    transactionHash: '0x70a589322708fba40c9816a089e78cab3628d8c3030e64b9fdee55d07c7cef97',
    address: '0x495f947276749Ce646f68AC8c248420045cb7b5e',
    topics: [
      '0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62',
      '0x000000000000000000000000c669b5f25f03be2ac0323037cb57f49eb543657a',
      '0x000000000000000000000000e34228f210354911c0fedad9941c7cfd269b9e91',
      '0x000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
    ],
    data: '0x65c91b1e502d798939f9f75d4710895e6315df770000000000013800000000010000000000000000000000000000000000000000000000000000000000000001',
    logIndex: 0,
    blockHash: '0x8edd5c489335ed9411724af5f0e9a565edd9b93e9ed306450d575ae8efd8268e'
  }
]
Sender balance:        0
Recipient balance:     1

If OpenSea administrators run this same transaction with their real private key this token would be transferred for real. (What you are seeing is a local copy of this transaction which ignores the fact that it is invalid for want of the correct private key.)

The above paragraph is a brief simplification. OpenSea Shared Storefront has recently changed from a single owner, to a Gnosis safe. No difference, to execute this transaction OpenSea administrators need to use only a slightly different process.

Debugging

Feel free to hack and try other things with this project. I learned about OpenSea Shared Storefront by decompiling it, printing in a word processor and using highlighters. Another helpful technique is to inspect transaction storage access and internal calls. To try that you can use a third terminal to run:

npx hardhat trace --fulltrace --rpc http://127.0.0.1:8545/ --hash 0xxxxxYOURxTRANSACTIONxHASHxxxx

Is OpenSea violating US Treasury OFAC/SDN sanction requirements?

Is OpenSea subverting sanctions by allowing sanctioned entities to hold digital assets that OpenSea has the ability to seize?

In their privacy policy, they already state that customer’s personal data can be used to comply with investigations by law enforcement and for other reasons.

But are they using this ability to seize tokens? And since OpenSea is obligated to stop transactions with sanctioned entities from the OFAR/SDN lists, are they using this ability to comply with this requirement?

To answer this question, I reviewed the historical list of OpenSea Shared Storefront token holders and then current OFAC/SDN sanctions lists to find if OpenSea has effectively stopped sanctioned entities from putting through transactions. Too much for this post, so stay tuned for a follow up post here.

How do decompile and study smart contracts

Because OpenSea did not publish the source code for this contract, it was necessary for me to decompile it to study it. If you would ever like to try the same approach with other popular but unverified smart contracts, below are some basic notes on the approach.

Here are some notes about how to effectively decompile and study smart contracts, read the Matrix. I recommend doing this on paper with color pencils/highlighters. You might have to take a lot of notes and this helps.

  1. Use Online Solidity Decompiler.
  2. Remove top-level contract, reduce indent, paste into MS Word or similar

Since OpenSea general produces intentional code, I was only looking for backdoors, code paths that results in a SSTORE.

  1. Replace revert.*; to REVERT
  2. Replace ` var.\W+REVERT. and memory.*\W+REVERT to REVERT`, go back and forth a few times
  3. In main function
  4. Find dispatches that result in return, replace with return; // does not change state
  5. On dispatch, mark in red any called function/goto
  6. On red things, mark in red any called function/goto, repeat
  7. Delete everything not red

You have completed the easy steps. Go to bed and do the rest steps with full brain power.

Acknowledgements

Reading circle questions

  • For artists, does this shared ownership with OpenSea affect your interest in publishing with them?
  • Does OpenSea’s ability to take tokens count as “ownership” in the same way that the token’s buyer is considered an “owner”?
  • Is OpenSea’s implementation compliant with ERC-1155’s transfer and approval specifications?
  • Is it necessary for a large company to publish their smart contract’s source code even when many people won’t read it?

Comments

Discuss and share this topic anywhere. May we recommend: