Hacking into the worldwide Jacuzzi SmartTub network

Eaton โ€ข

Discussion links: X | Reddit (gadgets, netsec)

News coverage:

June 22, 2022 update: Clarified that SmartTub shut down the smarttub.io admin panel themselves, and not Auth0.

July 25, 2022 update: Read the response Jacuzzi Group sent to their retail partners a month ago.

Background

Jacuzzi Brands is a widely recognized hot tub and spa manufacturer. There are several brands under their umbrella:

When you go to buy a hot tub, Jacuzzi is likely what comes to mind first, and you’d probably go check out offerings from Jacuzzi Hot Tubs. They make the best ones and have been in business a long time.

I ordered a hot tub from a local dealer in June 2021. Delivery took place in December 2021. As part of the order, I optioned the SmartTub feature.

What is SmartTub?

SmartTub consists of two elements: a module inside the tub itself with cell data reception that can access/control tub functionality, and an Android/iPhone app. The tub module is always connected to a central server, providing tub status updates and listening for commands. Command examples: turning on lights, jets, setting water temperate, and more. The module is OEM and can be installed as a factory option, or retrofitted at any time after delivery.

You could consider SmartTub an IoT/smart device. Aside from the Android/iPhone app, it also integrates with Alexa, Google Assistant, Wear OS, and Apple Watch.

SmartTub is available for multiple brands. Below is a screenshot from the app:

More about SmartTub on the Jacuzzi website

Setting up SmartTub

On delivery day I was eager to set up SmartTub. After waiting a little while for the dealer to do the pairing/activation, I created my account using the app and started messing around with it. I went to add the account password to my password manager and checked what website/URL should be associated with it. The account confirmation email came from smarttub.io, so that is what I used.

A flash of data

After setting the password in my password manager, I went to the smarttub.io site to see what was there. There was an Auth0-branded login page. SmartTub uses Auth0 for their login and user account system. If you don’t want to build your own login and user account system, Auth0 is a good choice and saves you a lot of time by providing a full & secure user account system out of the box. Anything you build from scratch is unlikely to be as secure as Auth0’s offerings.

I entered my details, thinking this was a website alternative to the mobile app. I was greeted with an Unauthorized screen:

Right before that message appeared, I saw a header and table briefly flash on my screen. Blink and you’d miss it. I had to use a screen recorder to capture it. I was surprised to discover it was an admin panel populated with user data:

Glancing at the data, there is information for multiple brands, and not just from the US. There are a few @jacuzzi.eu emails and a @hotmail.co.uk one, so it seems data from overseas is here too.

The unauthorized redirect makes further investigation impossible, so let’s try to bypass it!

Breaking in

smarttub.io hosted a single-page-application (SPA) built using React. Admin panels are commonly built as an SPA, so seeing it used here is unsurprising. I downloaded the JavaScript bundle and searched for instances of “unauthorized”. I found where it sets the URL to the error path, and also where it seemingly creates the unauthorized div:

If you look closely in the second image, it checks if the user is admin. If they aren’t, they get redirected to the unauthorized page. This is the isAdmin check:

The login works by sending the username and password to Auth0. On success, access and ID tokens are returned. The access token is then sent to Auth0’s /userinfo endpoint and this information is returned:

This information contains a list of roles, and isAdmin is checking whether Admin is there. In my case, it is not. If the HTTP response could be intercepted to add in the missing Admin role, it’s possible the unauthorized page would no longer show. I used Fiddler to modify the HTTP response accordingly, and I was finally able to access the admin panel in full.

Unrestricted Access

Once into the admin panel, the amount of data I was allowed to was staggering. I could view the details of every spa, see its owner and even remove their ownership:

I could view every user account, and even edit them:

Please note that no operations were attempted that would actually change any data. Therefore, it’s unknown if any changes would actually save. I assumed they would, so I navigated carefully.

A second admin panel

The first admin panel revealed user and spa information. That is pretty bad, but things get worse through the discovery of a second admin panel.

This second admin panel was discovered while reviewing the Android app APK. There is link to an admin console in a configuration function:

This login screen is not Auth0 branded, so I didn’t expect my credentials to work. I tried them anyway – they seemed to work, but I got a message saying I do not have permission:

This is a standard browser alert, coming from JavaScript code. Could the same bypass trick on the first admin panel be used here?

Breaking in – Again

I downloaded the JavaScript bundle. It’s completely different than the first admin panel, but still uses React. I found the code that shows the browser alert, and the isAdmin check.

There appears to be other groups besides admin and user. There is one for a “tools admin” and one for the development team. To get user information, the access token JWT is decoded client-side, instead of using it to call /userinfo. And, the groups section of the user information is being checked this time, instead of roles.

To attempt to bypass this, I used Chrome Local Overrides to load a modified JavaScript bundle file. The modifications I made were to simply change canUseTools, checkAdmin, and checkDevTeam to return true in all cases. This way, I didn’t need to intercept the HTTP response each time to modify the groups.

Logging in using the modifications worked and I could see the panel, populated with user data yet again:

It’s worth noting that being a member of the tools admin and development team groups unlocks additional menu options that are apparently off-limits to “normal” admins (under the More menu):

The spa and user access is mostly the same as the previous panel. There’s a few new options though, particularly an option to extend your cell data subscription (or shorten someone else’s…):

As for other internal sections, including sections that normal admins can’t even access, here is a list of what I observed could be done. Out of respect for Jacuzzi/SmartTub, screenshots of these private/secret/internal areas will not be shown.

Production Data

It’s worth noting that both admin panels are accessing the same data source/database, and are accessing production data. I confirmed this by looking up my own account.

User Data and California Laws

Worldwide user data was exposed, which included first name, last name, and email address. There is a phone number field, but thankfully I never saw it filled in anywhere, and you aren’t asked for it when creating an account.

It would be trivial to create a script to download all user information. It’s possible it’s already be done. Jacuzzi is incorporated in California which has data breach notification laws. I’m uncertain whether the exposed data meets the bar for the law’s requirements, and it may not be technically possible to identify California residents in the SmartTub network. Jacuzzi did not respond when I brought up the California laws.

Disclosure Timeline

All times in EST.

Summary: After multiple contact attempts through 3 different Jacuzzi/SmartTub email addresses and Twitter, a dialog was not established until Auth0 stepped in. Even then, communication with Jacuzzi/SmartTub eventually dropped off completely, without any formal conclusion or acknowledgement they have addressed all reported issues.

I would like to thank the Auth0 security team. Auth0 didn’t have to help since this was not their problem, but they did, and without their assistance, this disclosure would probably have remained stalled. I was happy to see they are willing to help their customers.

In the end, the second admin panel was secured. I wasn’t notified and decided to check it randomly one day because I wanted to start preparing this report. This is how it looks when I checked on June 4th, 2022 – after logging in, you get this message from the server and there is no way around it:

Dear Jacuzzi: I would like to discuss a few other security concerns not mentioned in this report. Please contact me – I want to help!

Subscribe to new posts

Get an email notification every time something new is published.
๐Ÿ“ง