Trello bug bounty: The websocket receives data when a public company creates a team visible board

We were in a meeting with some friends when one of them moved a card on the project's board, on my screen the card moved instantaneously, quite impressed I was wondering which technology was used to have this kind of real time events. I began digging and found out that Trello was using WebSockets. Actually, they use them a lot.

When you go on Trello a web socket connection is opened and each time a new event occurs, data are instantaneously sent to the web socket. It can be a notification, a new card or a new comment... The web socket will receive a little payload and the UI will be updated.

This payload can be private, for instance your Trello's notifications will be sent to you and only you, other people can't access them. To authenticate the user using a web socket, Trello use a token sent with the GET request, something like this:

wss://trello.com/1/Session/socket?token=51cc0b313cbab97d460038b9/2MDAf68quzJ5Cu2xsa96PJb2a8Rh84S34bHmMnbpR4xpBH4NvCUDhkCwS8dIllOp  

This is a common way to authenticate a web socket connection. From there a session is established with the server. Using the token Trello knows who owns the session and so can send the data according to the person's rights.

To receive data about a Trello model (board, card, ...) you must first subscribe to a model using a payload like that:

{"type":"subscribe","modelType":"Member","idModel":"51cc0b313cbab97d460038b9","tags":["messages","updates"],"invitationTokens":[],"reqid":1}

When the web socket server receives the payload, if you have the correct rights you will receive a positive answer otherwise an authentication message error. Once you have subscribed, you will receive data payloads about the model for each event that occurs.

The goal of my testing was to see if some data was leaked, for instance if using a token I could subscribe to the notifications of another user. The fact that you must have the rights on the model to subscribe to it is a good design. It removes lots of error cases, for instance it's impossible to subscribe to a user different than you or a team on which you have no rights.

It means that you have to find a case where you have the rights to subscribe to a model and potentially private data could be sent to you. That's the case for a team, if the team is public, everyone can subscribe to it, nonetheless the payloads sent to the web socket will be different regarding if you are a member, an admin or a lambda user. So I did the test.

Normally, when a user creates a board on the organization's page, if you subscribed to the organization you will receive a payload with the board's basic information. If the board is public, everyone will receive a payload, if the board is team visible only the team members will receive a payload and if the created board is private, no one will receive a payload (unless you are the admin of a business class organization).

Doing my test, I discovered three problems:

  • If the company is public, everyone receives a payload when a team visible board is created.
  • A user with an invitation token subscribing to a team always receives a payload when a private board is created.
  • A user with an invitation token subscribing to a team always receives a payload when a team visible or private board is created even if it is not part of the team (he has been removed).

I filled two reports for these bugs (#123984 and #126242), Trello awarded me a good bounty of $738 + $1024.

The web sockets are increasingly used and sometimes missed by the pentesters that focus on well established vulnerabilities, so it's worth checking them.