OpenSea "private" token list exploit

By William Entriken

4 minutes

Summary

The OpenSea website allows to mark certain NFTs as “private” or “hidden”. However this validation is checked on the client side and can be overridden.

Recommendations are given to update wording on the website consistent with the public visibility of this information.

Background

On the OpenSea website, a visitor can authenticate as controlling an externally-owned Ethereum account by signing a message to login. After that point, the visitor is able to set a profile and interact with non-fungible tokens.

The website allows authenticated visitors to mark some of their tokens as “private” or “hidden” and those tokens are not normally visible to other visitors to the site.

Proof of concept

I have logged into my OpenSea account and marked an NFT as “hidden”. By clicking on the “hidden” link on the page, I am taken to the “private” list of my NFTs so designated.

List

When attempting to open this same URL from private browsing (i.e. without cookies, no longer logged in) the page will normally not display those “private” NFTs. The following steps slows down what is happening and show the “private” information:

  1. Use a browser which supports developer tools (such as Chrome, Safari, Firefox and Microsoft Edge)
  2. Open developer tools (for Microsoft Edge on macOS, this is COMMAND-OPTION-I)
  3. Click the Network tab
  4. Enable Preserve log
  5. Visit the special url https://opensea.io/Su-Squares-CEO?tab=private
  6. Click the “Doc”/”Documents”/”HTML” filter
  7. Click the URL which includes the “tab=private” at the end
  8. Click the Response tab on the right area
  9. Copy/paste all this text into your favorite text editor

From this page you are now able to access all the “private” tokens for this account.

The following screenshot is loaded using private browsing (I am not logged in) and it shows the private NFT tokenID which is #2378.

Private browsing

Other approaches can automate this task.

curl 'https://opensea.io/0xF1ac3C963c377faf5737F41C294cA8C79565A610?tab=private' -H 'user-agent: Mozilla' > private.html

cat private.html | perl -n -e 'print if s|.*__wired__=(.*?)</script>.*|\1|' > private.json

cat private.json | jq

Discussion of severity

Of course, anybody could already get any of this information. “Simply” run your own blockchain node on every network, parse all the non-fungible token event logs, write custom parsers for non-compliant contracts, tabulate everything into a nice user interface. OpenSea has a strong presence in the market because doing these things is hard, and because they make it work so well. From a security perspective, we might say this “private” information is already available but if not for this process described above, it is expensive to get.

For a couple specific hard-to-properly-track examples regarding ERC-721 tokens, see the “sleepminting” approach where tokens are moved without the consent of token holders as well as the XXXXERC721 implementation where many tokens are minted without causing any Transfer events.

In a severity assessment, it is always important to consider the practical impact of a finding. To do this, I have reviewed the top token holders of the Su Squares contract to see if any of them have marked their tokens as “hidden”/”private”. Etherscan has a nice interface to show the top holders of Su Squares. After reviewing all holders of 100+ Squares, one of them was found to have marked tokens on OpenSea as “hidden”.

I reviewed to see if they were all spam NFTs and actually several of them were marked as "isVerified": true. I stopped looking at this point.

I can say from my experience that public disclosure of who owns an NFT, or inversely which NFTs a person owns, can have a strong impact on the perceived value on those specific NFTs, the NFT collection as a whole and possibly even all collections created by a specific author.

In summary, these reasons affect the impact level:

  1. Information is currently labeled as “private” on OpenSea
  2. It’s not trivial for normal people to otherwise get that same information
  3. This information can have a material impact on the perceived value of NFTs
  4. NFTs are directly traded for money, sometimes considerable sums

It is difficult to assess the financial impact here (i.e. the ability of people to trade on “non-public” information based on this). From the simple analysis above, of the 500,000 current trading OpenSea users, perhaps 1,000 people are impacted. Probably a low-medium rating is fair.

For likelihood, this is a single command line to run, and many people that trade NFTs are familiar with command line. A browser approach is also provided—so tools or dedication are not required here. Probably medium-high rating is fair.

Recommendations

Remove all references to “private” tokens in:

  1. The “hidden” tab URL query string
  2. The JSON used throughout the site
  3. Any other JavaScript or HTML comments

Update the support article How do I hide items from my OpenSea profile:

  1. Clarify the word “private” in this context
  2. Reduce the security guarantee by reminding visitors that all activity on distributed ledgers that OpenSea supports are publicly visible using other tools

Credit

This issue was discovered by David Scully / dscullywebdesign@gmail.com and written up for Privacy Log by William Entriken.

Disclosure schedule

Comments

There are no comments yet.

Please discuss this topic anywhere and let me know any great comments or media coverage I should link here.