Why your backend workflows might be your app's biggest vulnerability

Understanding and Securing Public Backend Workflows in Bubble

The Common Misconception

After misconfigured privacy rules, public backend workflows represent the second most prevalent security issue in live Bubble applications based on what I’ve seen from auditing dozens of apps. There’s a widespread misunderstanding about their security model that you may not be aware of.

Many developers assume that requiring authentication is sufficient to secure a workflow. However, this assumption is incorrect. When a backend workflow requires authentication, it only verifies one of two conditions:

  1. The workflow is called using an admin API token
  2. The user is logged in

The second condition is where security vulnerabilities commonly arise. I’ll walk you through a couple of examples.

Example Vulnerabilities

Example 1: Unrestricted User Deletion

Consider a recruitment marketplace with a backend workflow named ‘delete-user’. This workflow accepts a User parameter and performs the deletion operation. It might be public either by Bubble’s default settings or because it’s called from the front-end using the API / App Connector.

The security issue: When authenticated, any user can call this workflow without restrictions. From Bubble’s perspective, authentication is satisfied. This means any user could potentially delete other users as long as the privacy rules allow access to those user records - which in a recruitment marketplace could be a substantial number of users.

Example 2: Email System Exploitation

Consider a ‘send-email’ workflow that accepts three parameters:

  • recipientEmail
  • subject
  • body

Even with authentication required, this creates a significant vulnerability. Any authenticated user can:

  • Send emails to any email address
  • Include any content in the email
  • Have the email sent from your platform’s email address

This scenario creates a perfect vector for phishing attacks through your platform’s email system.

Just because a user is authenticated, does not mean that they should be able to run the workflow. Authentication is generally necessary, but is rarely sufficient.

How to resolve the issues

The appropriate solution depends on your workflow’s specific use case. Here are the detailed approaches:

1. Internal-Only Workflows

If the workflow is exclusively used internally (e.g., via Schedule API workflow):

  • Uncheck the ‘expose as public workflow’ checkbox
  • Deploy the changes live

2. External-Only Workflows or API Connector

For workflows called only from external APIs:

  1. Add a text parameter (e.g., key, token, or authKey)
  2. Configure the first workflow action as ‘Terminate this workflow’
  3. Add a condition: 'Only when key is not <your chosen key>.
    This creates a password-protected workflow that terminates if the key is incorrect.
  4. If calling the workflow from the API Connector, provide the auth key in a private parameter.

3. Workflows called by App Connector

Expand for details, as the solution is more complex. For workflows used both internally and called from the front-end via App Connector (where parameters cannot be private).
  1. Create a new ‘Permission Token’ data type with fields:

    • token (text)
    • User (User)
    • expiry (date)
    • used (yes/no)
  2. Set the privacy rule: This Permission Token’s User is Current User

  3. Before calling the backend workflow:

    • Create a new Permission Token
    • Set token = Calculate random string (use a long random string)
    • Set User = Current User
    • Set expiry = Current date/time + 1 day (don’t set this too short, else users with unsynchronized system clocks may not be able to authenticate)
  4. Pass the Permission Token’s token to the backend workflow

  5. Within the workflow, implement these checks:

    • Search for Permission Tokens where:
      • token matches the token parameter
      • User matches the User parameter
      • expiry is greater than Current date/time
      • used is no
    • Terminate the workflow if no matching token is found
    • Mark the token as used if found, then proceed

This verification system ensures the backend workflow is called within your app’s workflow context rather than through direct API manipulation. You can implement it easily using a custom event that returns a verified value (yes/no), and terminating the workflow when verified is no.

Identifying workflows at risk

You can go through your workflows to identify which are public, and determine if they pose a threat.

However, I’ve built a new audit tool which is available in early access that offers comprehensive security scanning capabilities (including for this issue):

Features:

  • Public data detection (bypassing data API)
  • Backend workflow exploit identification
  • Insecure and inefficient plugin detection
  • Misconfigured redirect detection
  • Automated issue fixing in the editor (one-click issue fixes)

The tool provides context-aware scanning - for example, it won’t flag public products in an e-commerce app unless they have specific sensitive fields.

Upcoming features:

  • Role-based privacy rule analysis
  • Internal app logic security vulnerability detection
  • App logic optimization opportunities
  • Interactive app analysis capabilities

While Flusk provides excellent ongoing monitoring, this new tool focuses on comprehensive point-in-time audits, for free. I hope that as Bubble begins to integrate security more directly into the editor, that this tool becomes less relevant, but I bet that I can build security tooling faster on Bubble than Bubble can built it into Bubble! :grin:

For early access to the free tool, visit: https://secure.notquiteunicorns.xyz

49 Likes

Thanks @georgecollier! This is super insightful about actually securing backend workflows in Bubble!

1 Like

Thanks @georgecollier Bookmarked :bookmark:

1 Like

Thanks @georgecollier ! Will be reviewing it for sure! :slight_smile:

2 Likes

Excellent post - and great initiative to create a Vulnerability Scanner, independent of Bubble. I’m sure Flusk will be a great addition to the Editor toolset but marking your own homework doesn’t really cut the mustard. :slight_smile:

3 Likes

Nice thread but don’t do this, math.random() is not cryptographically secure.

That’s not a huge issue for this use case. It is fine (and necessary) for the user to know their own permission token, and pseudo-randomness is good enough, when faced with the alternative. Worrying about the randomness (or lack thereof) of the string generated in this case would be like worrying about a papercut when the house is burning down. Generate one somewhere else if you want, but it’s more hassle than it’s worth.

1 Like

It’s equivalent to not having a token in the first place.

1 Like

Really interesting. Bookmarked

1 Like

Tell me, how are you hacking it knowing that math.random is not secure?

There are several blog posts on this exact topic, which you can look up yourself. Really poor argument. You don’t have to take my word for it by the way.

George, this is a general purpose way of handling this, right? Depending on the context, any condition could be used.

For example, if the workflow should only be called by Admins, then checking the user’s role would be sufficient.

Or am I missing something?

No, it wouldn’t.

The API workflow is public, meaning it can be called by anyone at any time.

Another way of thinking about it is as follows:

Just because a user is authenticated, does not mean that they should be able to run the workflow. Authentication is generally necessary, but is rarely sufficient.

If I have a public workflow ‘Delete User’ that I normally call via the App Connector, then inside the workflow, normally, I have no way of knowing whether that request came from the App Connector after we checked the user’s role, or just from someone tinkering in Postman.

The exception is if you use Current User inside the workflow / on the workflow condition (e.g Current User’s Role is Admin). That will ensure that it will only run when the current user is admin, but this implementation is rare outside of Schedule API workflow.

1 Like

I always appreciate security recommendations since many Bubblers are not developers and wouldn’t know to even think about this sort of thing. I see security vulnerabilities in my coaching sessions all the time. Some fix the issues based on my recommendation, others do not. Thanks @georgecollier :tada: Bookmarking for sure! :blush:

Added to the NoCodeMinute eLearning Hub :white_check_mark: (Just a link to this article for me to find it easier in the future)

4 Likes

Ah, gotcha. Thanks! Well explained.

It’s a shame the app connector has this extra workaround.

Really hoping Bubble ships returning data from internal backend workflows soon…

4 Likes

They are not, and have no plans to do so. This was asked during a live web session.

Bubble Product Sesh with VP of Product Allen Yang

They also hinted at this during the most recent Bubblecon. Essentially, they think it will lead to security problems, and don’t want to deal with figuring out how to do it properly. It’s during the talk with the engineer.

It’s a terrible decision and this is one of the top 3 things they need to be working on instead of playing around with the UI.

3 Likes

:exploding_head: didn’t know it was that easy to get through the authentication.
that means that without your technique any endpoint can be accede

Yep! Any public endpoint can be accessed if anyone can sign up to your app. They can call it whenever they want, and will only be restricted by any privacy rules that apply to the User making the request.

1 Like

Wow… what a disappointing video…

Not only have they got no plans to allow data to be returned from backend workflows, but it looks like ‘loops’ won’t be appearing any time soon (he said it’s on their radar, but they don’t have a timeline for it - that despite Bubble support telling me last summer that it was in active development, planned for release in the autumn/fall of 2023, which never happened).

100%

There’s at least 3 (I’d say 4) major things wrong/missing in Bubble which, in terms of capabilities/performance leave Bubble way behind some of the low-code/visual-dev competition, and it seems Bubble have no plans to address those (at least any time soon).

It’s pretty clear, from their focus on UI improvements and AI, the direction they’re going in and, unfortunately it’s not in the direction of plugging these holes in the platform’s capabilities, but rather making it a more attractive platform to new (and non-technical) users who want a quick and easy way to build an app - which is perfectly reasonable, of course, and it’s entirely Bubble’s prerogative what direction they go in and who their target audience is - but it does seem to contradict their own claim that Bubble is/will be every bit as capable as traditional code (given how much basic programming functionality is still missing from Bubble, that seems a long way off).

10 Likes