Zum hauptinhalt springen

Presents versus privacy

Burning gift box between building blocks

On the Internet no one knows you’re a dog creating content – but everyone knows you love support from your fans (whether in the form of technical devices, energy drinks or feed). However, it’s not a good idea to leave your home address online where overzealous fans or malicious stalkers might find it. For this reason, services have emerged that seek to enable creators to receive physical gifts without compromising their privacy.

But how good do they actually protect your address? Let’s have a look…

Cooking, sewing, ASMR or a combination of all three will easily get you millions of views on platforms such as TikTok, Twitch, YouTube or FurAffinity. For some creators, this is a hobby, while others make a living live streaming or producing videos. And very often: With support from their fans.

The world is a cruel place

In addition to direct monetary donations creators often offer their fans a more personal way to support them: wish lists for physical (or digital) goods. One convenient way to do that is Amazon’s Wishlist feature.

But we all know that the internet the world is a dangerous place. Private data is posted on the net (doxxing) and police “special forces” are directed to the homes of public figures by faking emergency calls (swatting). This goes beyond dangerous pranks - sometimes organized groups work to make life hell for their victims.

Problems of preserving privacy

More than enough reason for many creators to keep their address or even their entire identity a secret.

But the Amazon wishlist is not suitable for this because it displays the recipient’s name and city - not exactly ideal for anonymity. And there are even reports that it is possible to get Amazon to leak the complete personal data including the address - for example by manipulating employees (social engineering) or exploiting technical loopholes1.

And where there is a problem, there are startups trying to monetize it. (Platform marketing! Creator economy! Capitalism! Yay!)

Fear + StartUp = Profit

One of those startups is Throne. They launched in 2021 and promise to get creators their gifts while keeping their name and address secret:

Throne was created with privacy as our first principle.

We value our creators privacy and keep addresses entirely private. No fan will ever see your address, delivery name or any other identifiable information.

The Idea is simple: Creators compile a wish list of products from different stores. Fans then pick products and pay the corresponding amount of money to Throne. In turn, Throne uses that money to order the product from shops like Amazon - straight to the creator’s home.

For a slice of the cake2, of course.

Flowchart, showing how Creator, Fan, Throne and the Online-Shop work together

Graphic Design is our passion

This means that if you deem Amazon Wishlists too risky, you give your address to Throne so that Throne can enter it into Amazon’s order form. The important difference to Amazon Wishlists is that Throne acts as a “security layer” between the fan and the online shop.

This means the platform is sitting on a particularly sensitive treasure trove of data - the identity and private addresses of all the creators. So they better take care of it 🐉.

But you wouldn’t be reading this if they hadn’t screwed something up.

A throne made of bricks

But before we talk about the exact problem, we first need to have a look at how Throne is built.

That was also the first question we asked ourselves once we took a look at Throne. So we opened the developer tools of our browser and had a little look around the source code of the Throne website.

One thing struck us right away: Throne uses Firebase. You can think of Firebase as a set of software building blocks made by Google. Thanks to these building blocks, startups no longer need to worry about all the individual parts of an app. Many startups don’t necessarily want to run such complicated things as file storage, authentication services or databases themselves. They can outsource all that to Firebase – and focus on the core of their startup software development, or whatever else it is they actually do.

One of its components is the Firestore. It’s a database, the long-term memory of the application. It stores data in collections – roughly comparable to tables of data.

This database can then be queried: What items does a certain creator have on their wish list? And how much do these cat ears actually cost? And where can we get them? We also want nice and fluffy cat ears!

But not all data should be read (or written) by everyone. To ensure this, developers have to configure proper security rules.

And Throne has done this successfully for much of the data. For example, when asking the Firestore for all addresses, it denies the request:

// curl -H "Authorization: Bearer ey[...]" https://firestore.googleapis.com/v1/projects/onlywish-9d17b/databases/(default)/documents/deliveryDetails

{
  "error": {
    "code": 403,
    "message": "Missing or insufficient permissions.",
    "status": "PERMISSION_DENIED"
  }
}

But if we only ask for our own address, the query is successful:

// curl -H "Authorization: Bearer ey[...]" https://firestore.googleapis.com/v1/projects/onlywish-9d17b/databases/(default)/documents/deliveryDetails/[ZERFORSCHUNG USER-ID]

{
  "name": "projects/onlywish-9d17b/databases/(default)/documents/deliveryDetails/[ZERFORSCHUNG USER-ID]",
  "fields": {
    ...
    "city": {
      "stringValue": "Musterhausen"
    },
    "postcode": {
      "stringValue": "12345"
    },
    "address1": {
      "stringValue": "2342 Hack Blvd."
    },
    "address2": {
      "stringValue": ""
    },
    "state": {
      "stringValue": "Berlin"
    },
    "country": {
      "stringValue": "DE"
    },
    "lastName": {
      "stringValue": "forschung"
    },
    "delivery_instructions": {
      "stringValue": "deliver to the pink unicorn"
    },
    "hasIssue": {
      "booleanValue": false
    },
    "name": {
      "stringValue": "zer"
    }
  },
  ...
}

Unfortunately we already had a case (Article in German) where these permissions were not set correctly, and we could also ask for internal access data. And it was similar here:

A single failed request didn’t stop us from experimenting further to figure out what data we could query. We (mostly3) just received data that we should be able to see.

But after further digging, we found a collection called constants that we had access to. It contained all kinds of things: For example the conversion rates of various currencies4 or a list of merchants offered by Throne. But also some credentials:

Excerpt of constants collection (Click to expand)
// curl -H "Authorization: Bearer ey[...]" https://firestore.googleapis.com/v1/projects/onlywish-9d17b/databases/(default)/documents/constants

{
  "documents": [
    ...,
    {
      "name": "projects/onlywish-9d17b/databases/(default)/documents/constants/exchangeRates",
      "fields": {
        "CHF": {
          "doubleValue": 1.1060111707128242
        },
        ...
      }
    },
    {
      "path": "constants/bannedDeliveryDetails",
      "data": {
        "addresses": [
          {
            "searchableName": "████",
            "delivery_instructions": "",
            "postcode": "███",
            "city": "█████",
            "googleMapsFormattedAddress": "██████████████",
            "updatedAt": 1657348████,
            "firstName": "███████",
            "address2": "",
            "geo": {
              "lat": 26.██████,
              "lng": -80.█████
            },
            "lastName": "████",
            "phone": "████████",
            "country": "US",
            "address1": "██████████",
            "state": "███",
            "hasIssue": false,
            "reference": {
              "type": "creator",
              "id": "██████████████"
            },
            "name": "█████ ██████",
            "searchablePostcode": "███"
          },
          ...
        ]
      }
    },
    {
      "path": "constants/gsheetsOAuthToken",
      "data": {
        "access_token": "ya29.████████████████████████████████████████████████████████████",
        "expires_in": 3599,
        "token_type": "Bearer",
        "scope": "https://www.googleapis.com/auth/spreadsheets",
        "expires_at": ███████,
        "refresh_token": "████████████████████████████████████████████████████████████████████████████████"
      }
    },
    {
      "path": "constants/trackedAmazonAccounts",
      "data": {
        "trackedAmazonAccounts": [
          {
            "cookie": "████████████████████████████████████████████████████████████",
            "countryTld": "co.uk",
            "name": "Amazon UK"
          },
          {
            "name": "Amazon FR",
            "countryTld": "fr",
            "cookie": "████████████████████████████████████████████████████████████"
          },
          {
            "name": "Amazon IT",
            "countryTld": "it",
            "cookie": "████████████████████████████████████████████████████████████"
          },
          {
            "countryTld": "de",
            "cookie": "session-id=███████████████; ubid-acbde=███████████████; av-timezone=Europe/Berlin; csd-key=e████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████; sp-cdn=J4F7; lc-acbde=en_GB; session-token=████████████████████████████████████████████████████████████; x-acbde=\"████████████████████████████████████████████████████████████\"; at-acbde=████████████████████████████████████████████████████████████; sess-at-acbde=\"███████████████████████\"; sst-acbde=████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████; i18n-prefs=EUR; csm-hit=████████████████████████████████████████████████████████████&adb:adblk_yes; session-id-time=██████████",
            "name": "Amazon DE"
          },
          {
            "cookie": "████████████████████████████████████████████████████████████",
            "countryTld": "es",
            "name": "Amazon ES"
          },
          {
            "name": "Amazon US",
            "countryTld": "com",
            "cookie": "████████████████████████████████████████████████████████████"
          }
        ]
      }
    },
    ...
  }
}

Most of these credentials were expired or useless without further context.5 Unfortunately, there also were session cookies for a bunch of Amazon accounts.

While we like cookies in general, these are not the tasty ones.

🍪 Cookies are a technology that allows websites to store a bit of information in users’ browsers. For example, a website can say, “Great, you successfully logged in with your password. Here’s a very special cookie. If you show it to me, I’ll always know who you are. So don’t give it to anyone else.”

If you have enabled two factor authentification (2FA) on an account1, the website also remembers this with the cookies it gave you - and doesn’t ask each time.


  1. 2FA is a important security precaution and you should really use it anywhere it is possible. ↩︎

But Throne didn’t keep these cookies to themselves. Instead, they allowed everyone to read them from their database. And anyone who has these cookies can show them to Amazon – and is authenticated as Throne.

This even works if two factor authentification (2FA) is enabled for the account, as the cookies store that you already completed 2FA.

Since we are now logged in as Throne, we can look at all orders they placed on Amazon - and of course, this includes the delivery addresses of the creators.

Redacted Screenshot of an Overview of Amazon Orders

Throne saved these cookies in a sub-collection named trackedAmazonAccounts. This suggests that they use the cookies to allow a system to automatically check the status of the order and allow gift recipients to track the shipment. However, this does not excuse the publication of the cookies to the whole world.

Ding-dong

After we found the security issue, we put together a report and sent it to Throne, CERT-Bund (the German federal computer emergency response team) and Berlin’s data protection authority6.

About 45 minutes later, they informed us that they closed the security vulnerability.

That was pretty fast – even for startups, which often brag about their agility. And Throne’s next steps seemed sensible: Invalidate the Amazon cookies to make them unusable and try to check if anyone else has exploited the loophole.

Also, Throne added a security.txt to their website following the recommendations in our report.

The security.txt is a standardized file for specifying contact details for security issues. Website operators can publish one to let security researchers know where to report a security vulnerability.

Better safe than sorry

Throne also published a blogpost on the incident. Unfortunately, they decided to downplay the issue and it’s implications.

Throne claims:

we investigated if users were affected and if there was any risk to personal data. Using IP logs we discovered that there was no risk and no unknown party had viewed any data.

We don’t know how exactly Throne determined this – they never asked for our IPs or any other identifiers to reliably attribute the access to us.

And even if they were able to attribute all queries: We could still access the data. We may no longer be an “unknown party” - after all we reached out to Throne. But we aren’t authorized to have access to this private information. And less wellmeaning actors could have done a lot of damage with this data.

Move slow enough - so you don’t endanger people!

In addition, however, a quick response to a security report is not enough: Once you’ve received the report it’s already too late. One such mistake can endanger many people – and it leads the whole privacy-claim of Throne ad absurdum.

Startups love the mantra “move fast and break things”. But when it comes to personal data, this is exactly the wrong approach. Privacy and security require a comprehensive strategy. This includes a well-thought-out software architecture and experience with the rough edges of the frameworks. All of this takes money and - often even more scarce for startups - time.

🤝

We reported on this issue together with TechCrunch. Their article can be found here.

Timeline

  • 2023-03-29: We’ve found the issues
  • 2023-03-30: Report to Throne, Berlin State Data Protection Commissioner and CERT-Bund.
  • 2023-03-30: Response from Throne, short phonecall with them
  • 2023-03-30: Throne reports that the issues have been fixed & further steps are planned
  • 2023-03-31: Throne publishes security.txt
  • 2023-04-05: Throne notifies their users

Disclaimer

Two members of zerforschung know one of the founders of Throne, but had no contact with him for several years prior to the discovery of the vulnerability.

After reporting the vulnerability, Throne bought us an electric tool we had on our Amazon wish list. We have never asked Throne or any other company we reported vulnerabilities to for money or gifts.

Neither of this is influencing our current or future reporting on Throne.


  1. https://parkerhiggins.net/2016/01/earlier-amazon-backdoor-exposed-wishlist-mailing-addresses/ ↩︎

  2. https://jointhrone.zendesk.com/hc/en-us/articles/4406704279572-What-fees-do-you-charge- ↩︎

  3. Although, we’re not sure if they intended to display the user flag isUnderInvestigation 🤔 ↩︎

  4. Weird, aren’t conversion rates changing all the time? Not particularly constant data… ↩︎

  5. For example, we found API keys for Google Spreadsheets. As far as we understood, we can’t do anything with those without knowing a document ID. ↩︎

  6. Thrones german subsidary is based in Berlin. ↩︎