The Ultimate Guide to Bubble Security is out - 300 pages of privacy and security content


Thanks for the thorough response – and yes, I agree with what you’re saying about the Unique ID after hearing Bubble’s response and giving it some thought.

I think understanding Privacy Rules also comes down to what your mental frame is: thinking about searches as a purely technical way to fetch data might leave you surprised that Unique ID’s will produce a result. However, thinking about searches in terms of discovering data shifts this frame, and it makes more sense that any UID that you already have knowledge of is per definition not discovered but has already been divulged. As such, you should set up your app to stop any User from discovering any data at all that they’re not supposed to have access to.

It’s easy to think of scenarios where a Unique ID might be misplaced (accessing the local device or Users sharing a link or screenshot for example), but with protected fields (privacy rules) and actions (constraints) adding additional layers of protection, I think it also makes sense to draw a line somewhere in terms of security paranoia.

I don’t really see the UID lookup as a Bubble vulnerability: my bigger concern is the degree to which Bubble devs are aware of these mechanics. I suspect many are unaware that a Thing identified by Unique ID in the Page Thing URL or a URL parameter will load (like my examples in the earlier post) and can be written to by an unprotected action. Technically there’s nothing wrong, but educationally that may still be a hole that hasn’t been properly filled. Bubble makes most things related to web development easy for beginners, but from what I’m seeing in coaching sessions they still haven’t quite finished the puzzle when it comes to communicating security best practices and the consequences for those outweigh those related to performance, design and other topics.

As for plugins, yes, that’s a chapter on its own. I’m not a plugin developer myself, so I honestly have limited to offer in that discussion but I would very much welcome a lot more strict vetting process from Bubble’s side to ensure security, version testing, etc.


I have added a new section in the book today that highlights the difference between a search and lookup discussed in this thread and how it affects security. The update is FREE for all buyers of the book.

The new section is available on page 151, and can be downloaded from your Gumroad library page:

For those who haven’t made the purchase, the book is available here: The Ultimate Guide To Bubble Security - How To Create Secure And Privacy-focused Apps In - Amlie Solutions


I have a doubt you want to clear up with you regarding server vs client side conditions.

I’m saving a database thing on a custom state.
Would the following condition make a workflow safe?
“Group A’s Event’s Admins contains current user”

I am not sure whether this condition is checked client-side or sever side, as it falls somewhere in the middle of the examples you give in the book (“element is visible” and “Current user’s administrator is yes”)

Thanks for your time and thanks again for your book.

1 Like

Thank you for your help! I’ve implemented the check for IP address and the signature timestamp freshness. I already feel safer.
I am not sure how you managed to authenticate stripe though. If I uncheck run without authentication, Stripe’s webhook just says that it is unauthorized. Any tips/suggestions on how to authenticate Stripe?

1 Like

@petter Congrats Petter! Have been waiting for this since our last chat. Just purchased and can’t wait to read it!

1 Like

@petter Just wanted to say I’m 144 pages in and cannot stop reading. Not only is it comprehensive with a wealth of context, but with such a delightful prose. :muscle:t2:

1 Like


If I try to understand your set up here, you have a GROUP A which contains a CUSTOM STATE (list of Users) that may or may not contain the CURRENT USER?

I would not expect that to run server-side. Since the list is not stored in the database but relies on a variable stored on the device, it can be manipulated. So no, this doesn’t look like a secure way to set it up. If you store the list of Users in the database instead, Bubble will be able to confirm it on a server level.

Let me know if I misinterpreted your scenario.

Thank you! I look forward to hearing what you think, and to our next chat :slight_smile:

Thank you so much Peter, that makes my day :slight_smile:

Thank you Petter!
My scenario is slightly different, but thanks for clearing up that scenario as well!

I have a GROUP A, which contains a Data Thing EVENT, whose field ADMINS (list of users) may or may not contain CURRENT USER.
A similar conditional would be GROUP A, containing a Data Thing ACTOR, whose field ADMIN (Yes/No) is Yes.

These seem like conditions which can be checked server-side, however the Database Things are stored on a custom state. Can a motivated malicious actor actually change what Thing is stored on the element’s custom state in order to make the condition pass?

You have ingrained in my head that client-side is no man’s land, so i don’t trust custom states anymore either.


Hmm, that’s hard to say - technically they might be able to replace the ID of the Event in that custom state and successfully check a different Event for the list of Admins. But it would require that they actually know the ID of an Event that lets them pass the condition in the first place and it’s also perfectly possible that Bubble has safeguards in place for scenarios like this.

We’re moving into territory now where I’d caution against being too paranoid about potential security issues. If we’re talking about particularly sensitive data/workflows here I would consider reaching out to Bubble to ask, and perhaps moving it to the server altogether to be safe (i.e. Current User’s Current Event’s Admins). But the scenario you describe of exploiting the Unique ID of a different Thing may be within the realm of possible but unlikely.

I definitely recognise the urge to map out any potential security issue in my head, and I of course can’t really advice against that - but it’s important to find the right balance so as to not overcomplicate things.

Very good book! Thank you very much!
I am however with a rather complicated problem and would like an opinion. I originally created this thread Dynamic fields in workflows are secure?

The objective is quite simple : I want to use an external service that I access through API using OAuth2 authentication. The problem is that the service has an production and development environments and it is crucial to differ between them (when using bubble dev, it should use the service’s dev environment). This differentiation is done in two parameters : the endpoint URL and the OAuth2 token (even the endpoint url to the Token generator is different in dev and prod).

Bubble support for OAuth2 is safe, but it does not support different tokens and different urls for dev and prod. So, I was manually getting and managing the tokens in the data base, but this require to use “Do Search for Token-Object”, so it must be searchable by the User and any User would be able to see it. I thought of moving the API call action to a backend workflow, but I need to show the response in the page and there is no simple way to send it back to the front.

Is there any possible secure way to use a data (the token) in an API without the user being able to see it and without using Backend Workflows?

Moving it to the backend would be secure, but not always practical.

You could also set up two different API’s in the API connector (identical, but with different keys) and alternate between them with conditions on the workflow depending on whether you are in live mode or not?

Yes, in the public pages I’m moving the API requests to backend (there are just two simple requests). However, the internal pages (for our staff) are way more complicated and I’m not sure how to proceed still.
I’ve contacted Bubble support and, for now, they advised in using two APIs but this would imply that bubble don’t recognize their response as the same object. It would imply in duplicating A LOT of workflows or saving every response as a database object. I find both ways very inefficient (first is prone to error and second bloats de database). Just answered them, so this is still an open case.

Hmm, yeah, I can see that’s a cumbersome solution. Another one is to switch the keys in the API connector before deploying and then going back. Gets you out of creating workarounds. But not very elegant.

To my readers in Japan :jp::

The book is now available in Japanese thanks to the translation efforts of Idea Garage. Check out the limited time release sale on: before September 30th.

Hello @petter

Thanks again for this book!

Something that I keep questioning myself is about the section:
“Client-side vs server-side conditions: it’s all about the action” - Page 166

In the case that I have a search being performed inside of a Popup (Do a search for Users), if I use this search as a condition to run a workflow, is this workflow insecure?

For performance and reference reasons, would be great just to do the search once (in a Popup for example) and reference it elsewhere (also as conditions for the workflows.)
But this section got me to think if it could be unsafe.

I asked this question myself a couple of times, so wanted to hear from you.


1 Like

Hi @NetoCamarano,

Yes, this is a server-side condition and can be considered secure. The exception is if you move the results away from the server and over to the client, such as saving the result of the search in a custom state. In that case it basically becomes a static, client-side value that’s no longer technically a search.

Hi @petter , around page 150 of your book you go into searches vs lookups, I’m now wondering what the implications of using “Current Users Something” is with regard to app security. If I just want to retrieve a single record, I was under the impression that using satellite data groups with this structure was the most efficient way rather than doing a complete search, but now I’m not sure. Assuming everything is protected correctly within privacy rules, what are the implications of using Current User’s ____ to RETRIEVE data. Basically, is this only a problem when doing client-side workflow actions? Thanks!

@randomanon bare in mind “current user” will always be empty on the server side unless one of two conditions happen

  1. api is triggered from client side from a logged in user
  2. you pass an authorization header you get from hitting a backend workflow “login” action.

Otherwise current user will always be empty.

In addition to #1, what if I have a backend workflow where I Create/Make a change to a Thing and set User = Current User?

But mostly I’m wondering about the security implications of a Group or Repeating Group that is “searching” for a Current User’s Thing (to speed up performance).

If user is a param then it will use it, however since #1 stated it was a scheduled API from client side from an authenticated user then “current user” will work.

An example of where “current user” will not on the backend is if you are hitting the API as a non logged in user from client side OR are hitting it from an external source without passing an authentication header with a valid user key retrieved from login. Because in these two cases there is no “current user”.

So in these cases you’d have to pass a user param but if security is setup correctly privacy rules will protect that meaning nothing could be changed or returned even if you pass the user as a param because the user is not authenticated.

Bear in mind backend workflows respect privacy rules unless you check “ignore privacy rules” (almost never recommended).

In a very dumbed down explanation the way searches work is like a tree
1- bubble server
2-client side constraints on do search for (same as “current user” essentially)
3- :filtered and :sort etc operators

Each are “iterations of the search following each other.

Privacy rules protect the 1st level (bubble server)

This is where we say who can and can’t pull what data from the server. Meaning if you have a data type called “message” with a field user and that message privacy rule says “only visible when user of message = current user” then no one else can pull from it regardless of if you’re using do search for, current user, or any other method.

This is because the front end client side is below the server side which is where privacy rules protect.

Alternatively let’s say you store a list of messages on a user. You reference “current users messages” yet you leave messages privacy rules empty. You will be able to return any users messages by using do search for and anyone who uses the data api using /obj/messages will be able to retrieve all of your messages because they lack privacy rules. So even though you stored them on the user you left the messages data type open in this case.

I believe this answered your question.

When testing security I’d highly recommend @flusk app to test out what you’re leaving open.

1 Like