I have a multi-profile app where each user has a separate Bubble user account per role (e.g. one per company they administer). To switch between profiles, I use a frontend workflow that:
Assigns a temporary password to the target user
Logs the current user in as that user using the temporary password
The frontend filters the list of switchable users to only show the current user’s sister/child users (those sharing the same master user), so from a UX perspective this is locked down.
The vulnerability
During a security review, the reviewer used an interceptor (e.g. Burp Suite) to intercept the POST call to /api/1.1/wf/start that triggers the workflow, and modified the user ID parameter to point to a completely unrelated user. Bubble’s server executed the workflow with no server-side check that the target user was a permitted switch-to target — and they were able to log in as any user in the app.
Note: this is not the known issue where SetTemporaryPassword exposes the generated password in the network response. I’m aware of that and it’s acceptable in this context since the regular UX only permits temporary password creation for sister profiles. This is specifically about the workflow accepting an arbitrary user ID with no server-side authorisation check.
What I’ve considered
The fix clearly needs a server-side relationship check before the temporary password is assigned. The natural solution is a backend API workflow that verifies the relationship (current user is sister of target user) before proceeding — but internal ScheduleAPIWorkflow calls are async and can’t return values to the frontend.
So I’d have to call it as a public API workflow via the API Connector to get the temp password back to the frontend synchronously; with that public API requiring user authentication via a token. But I don’t love this solution; it feels like it adds a lot of complexity, plus opens up a new attack surface (e.g. credentials stuffing in that API).
My questions
Has anyone found a cleaner solution to this pattern that avoids returning any credential to the frontend?
Has this intercept/replay/ID-substitution angle been discussed elsewhere on the forum? I could only find the separate SetTemporaryPassword password-visibility issue.
This is expected behaviour, and I believe the security dashboard flags this to you.
Specifically, here’s why your implementation is secure:
This means that your workflow references Parent group's User where Parent group’s User is the cell the user is switching to. That’s actually just an ID.
This is an oxymoron - UX is not related to security here
So, your workflow accepts an arbitrary user ID (which the user selects from the list). That means the user can manipulate that ID to be whatever they want to be.
The quickest way you can secure this is with a workflow condition that checks Parent group's User's Master Account is Current User's Master Account or something. I don’t know how you verify the relationship of the users, but basically you need to ensure that you verify, in relation to the Current User, that the User they’re providing is one they have permission to deal with.
In any case, the best practice here is not to have separate users, but separate Profiles/Accounts/whatever you want to call them, where a single user has multiple Profiles.
Support can be reached @ Home | Bubble Support Center - they’ll tell you what I told you though! Bubble itself prioritises security, but ultimately you need to build in Bubble in a secure way.
I hope the explanation above explains why this is possible and how you can secure it!
Super helpful, thanks George. Yes, it would be simple to add a workflow condition that checks precisely what you wrote. And indeed if I were to move it to a back end workflow, this is the condition I’d include to lock it down.
What I wasn’t sure about was whether putting that same condition in a front end workflow makes it easy for a malicious actor to circumvent. E.g. is there some mechanism whereby they can “bypass” the conditional because it’s in the front end rather than the back end?. From your response I’m assuming that no, it won’t be less secure, in which case you’ve solved my problem, thank you!
PS: I’d have preferred to have separate Profiles/Accounts for a single user. But the problem I ran into then was that the privacy rules are quite limiting. For example: each company has multiple users, and each user can have permissions to manage more than one company. So if I want a user to be able to see who are the other users associated with that company, then with User/Profile structure I need a privacy rule like “if this User’s Profiles: each Company intersects with Current user’s Profiles’ Companies”. (which you can’t do)
No, because in the frontend, the condition would be, let’s say, Current User's Master Account is Parent group's User's Master Account. Someone can manipulate Parent group’s User’s Master Account, but they can’t manipulate Current User, because that’s who they are. They can’t just ‘become’ another Current User without being logged in as them.