Thank you for the kind words!
1 - Notes/comments
No, notes/comments are contained within the editor files and do not transfer to the live app from what I’ve been able to find. If you perform a network-wide search in devtools (this short article describes how), you’ll find the comment if you inspect a Bubble editor tab, but not when you inspect a live app. This is true even if you reference the option set somewhere on the page. Note that I have only tested this for option sets, but I would expect that logic to apply everywhere.
2. Privacy Rules and Actions
This is a great question and I’m glad you brought it up since it’s a potential vulnerability. This will be a longer reply, so buckle up. I want to try and shed some light on two parts of it to clarify.
The first is the importance of understanding the difference between not being able to write to a Thing because of Privacy Rules (by disabling auto-bind) and not being able to write to a Thing because a Thing cannot be found (by disabling Find this in searches).
As you say, you will not be able to save changes to a database record that Bubble can’t find (because of Privacy Rules), but it’s important then to understand that it’s not the action that is stopped on a server level: the action (i.e. Make changes to a Thing) is running just fine, but since the record can’t be found (protected by Privacy Rules) there’s technically nothing to make changes to, and so the pen is there but there’s no paper to write on, so to speak.
While this in many cases can theoretically provide the protection you need, there are potential scenarios where this can give you a false sense of security. To understand this, we’ll need to define the difference between a search query and a lookup query. Performing a search means to send a call to the server with specific constraints to return a list of zero, one or more matches (such as all users with the last name Amlie). A lookup means to send a call to the server to fetch one record based on that records index key (what in Bubble is called its Unique ID). In that case you’ll only ever produce one result, and always the right one (such as the User with the Unique ID 163247823748237)
The challenge for Bubble developers from a security standpoint is that it’s not always clear when one method is used over the other. Privacy Rules are 100% consistent in how they function: the Find this in searches setting will completely disable the data from being found in a search. But when the Thing is referenced directly by use of its Unique ID, the query type changes to lookup and circumvents the Find this in searches rule. In most cases this is expected, but in other it can be confusing. I’ll illustrate this with three scenarios that I personally would rank as follows:
- completely expected
- not obvious but understandable
- surprising (but explainable)
All scenarios will discuss a User A that wants to make changes to a User B, and we’ll assume that the User type has the strictest Privacy Rules applied (can’t find in searches, can’t autobind and can’t view any fields):
Scenario 1: Direct database reference saved on Current User
In the first scenario, we’ll reference a Thing by use of a direct database connection: User B saved in a Field on User A such as Current User’s Boss. A Make changes to a Thing workflow using that field would would predictably work regardless of Privacy Rules, since this is a lookup (we’re not searching for the Thing):
The only Privacy Rule that can stop the above action from completing successfully is if the field Boss on the Current User is hidden, in which case the action will still run, but it will be trying to make changes to an empty record. But no other Privacy Rule will stop this change from being made.
Ok, everyone who knows their Privacy Rules knew this one. Onto a less obvious one:
Scenario 2: URL parameter
In this example, I’m in an app that relies on URL parameters for navigation and for fetching data. Someone has emailed me (User A) an URL that points directly to an Edit user form for User B, such as www.myapp.com/page?window=edituser&user=16872384726387462388765
When loading the edit form, User A will not see any of User B’s information since all fields are hidden, but User B is loaded into the form - since the Unique ID is not hidden by Privacy Rules and I’m not relying on a search to find the User. Technically, this is a lookup In other words: if I make any changes to that User with an action, those changes will be saved to User B with no problems:
Setting up a URL like the above is fairly common, and I don’t see any reason to discourage it, but I wouldn’t be surprised if even experienced devs reading this are unaware that the record is technically there and can be made changes to. Many experienced devs are indeed surprised to see that the Unique ID field can’t be protected by Privacy Rules at all, since there’s rarely any reason to look for it.
The reason this works is the same as in scenario 1: since Bubble has the Unique ID of User B, it’s not performing a search behind the scenes; it’s performing a lookup, which Privacy Rules don’t protect.
Example 3: Do a search for with Unique ID as constraint
In the third example, we’ll do the same as above. We’ll assume that someone sent User A the Unique ID of User B. But this time, we’re not passing that ID through a URL parameter. Instead, we’re performing a Do a search for and making the changes to the result of that search. Since we have not enabled Find this in searches, surely the result will be empty and the action will attempt to write on an empty record:
What you’ll find if you try this is… * gasp! * that even this
action will complete successfully. You’ll find the record even if it shouldn’t be searchable, and the action completes as if no Privacy Rules had been set up.
Why is that? The reason is the same as in the earlier examples: Privacy Rules adhere to what’s happening under the hood. Whether we as the app editor thinks we are performing a search is irrelevant to Privacy Rules - it only cares about how Bubble actually sends the query.
As soon as you use a Thing’s unique ID as a constraint, the query changes from search to lookup and is no longer protected by Privacy Rules - you’ll find the record with no problems and can make as many changes to it as you like.
Should it be this way? Honestly – I’m not sure. From a traditional web development perspective I’m sure this makes perfect sense, but to a Bubble developer with no knowledge on SQL queries it makes Privacy Rules appear inconsistent, since we’re obviously on the surface performing a search here.
All of these scenarios can and should be easily solved of course by placing an additional server-side condition on the action itself. In other words, you should never rely on a record being empty as a means of security: as long as the action is allowed to run, there’s a risk of some scenario where it’s not empty after all.
I’ve flagged the scenario to Bubble as a potential vulnerability, but it’s not given that they see it that way. Since it’s technically correct (and maybe impossible to change without breaking a lot of other stuff) there’s a fairly big chance that this is simply how it’s supposed to behave and they’re not going to change anything. From my perspective, the number of apps affected by this is likely quite small, but not non-existent: I am concerned that some devs are not aware of it since it’s not really communicated anywhere.
I’ll probably address this issue in an upcoming update to the book or a separate article, but want to get some clarification from Bubble first and at the very least get a confirmation that I’ve interpreted this all correctly. Everyone reading this should be aware that until we have it confirmed, my understanding could be incorrect in a minor or major way.