Blog
·9 min read

Migrating Bubble Privacy Rules: Test Who Can See and Change What

A rebuilt dashboard can look right while one customer can request another customer's records. A successful login and a matching database count will not catch that mistake.

To migrate Bubble privacy rules safely, turn the intended permissions into a written access model, implement that model at every relevant server boundary, and test both allowed and forbidden requests. Copying rules into generated code is a starting point for review, not evidence that the replacement preserves access.

This guide focuses on authorization: what a visitor, user or service may do. Login and account recovery are separate problems. So is proving that records and relationships arrived intact; use the Bubble data migration checklist for that work.

What needs to move besides the privacy rules?

Move the intended access behavior across records, fields, searches, files and actions. The Privacy tab is one input. Workflow conditions, API authentication, privileged background jobs and public endpoints can also decide what someone can reach or change. An inventory of checkboxes alone misses those paths.

Start with the live app's actual configuration and a safe test environment. Record data types, user roles, organization membership, ownership and exceptions. Ask the product owner which behavior is intentional. If the old app exposes something it should not, reproduce the test that reveals it, but agree on the corrected policy rather than preserving the leak as a feature.

Bubble's privacy-rule reference says that when several rules apply, access can be granted by any one of them. Review combinations, not just individual rules. A restrictive-looking owner rule does not cancel another matching rule that grants broader access.

Keep a separate list of public content. A public product name and a private supplier note may live on the same record. “Customers can read products” is too vague to specify which fields should leave the server.

Which Bubble behaviors are easy to translate incorrectly?

Separate finding a record, reading its fields, downloading its files and changing it. These are different permissions. Your replacement may enforce them in different layers, so check the result of each operation rather than looking for a one-to-one match between Bubble checkboxes and database policies.

Search access is not the whole read policy

Bubble distinguishes search visibility from field visibility. Its privacy-rules guide also explains that hiding a record from searches does not prevent every other way of fetching it. Test a known record ID as well as a list page.

Inventory search constraints too. A field hidden from the response may still reveal information if a caller can probe it through filters or counts. Record whether the app uses Off, Automatic or Strict search privacy mode, list the intended constrainable fields, and test Data API constraints separately. Make the replacement's searchable fields explicit. Do not assume that leaving a field out of the JSON response solves every disclosure path.

Workflow changes need their own authorization

Bubble's Workflow API privacy documentation distinguishes data visibility from workflow actions. The Data API's create, modify and delete permissions do not govern API workflows. A workflow can also be configured to ignore privacy rules.

For each action, document who can invoke it and what it may change. “Can read the invoice” does not answer “can cancel it.” Check workflow conditions and privileged exceptions before implementing the replacement endpoint. Inventory auto-binding separately; restricting it does not prevent workflow changes.

An administrative export is not an end-user access test

According to Bubble's Data API privacy rules, authenticating with an app API token grants administrative access and bypasses privacy rules. A successful migration export therefore tells you little about what an ordinary user should receive.

Keep migration tooling separate from normal request handling. Run acceptance tests using the application's intended user identities, plus separately scoped service identities. Do not put an administrative token in a browser or treat the importer's broad access as the new app's permission model.

File access is a separate boundary

Bubble's file guidance explains that private uploads require both the upload configuration and privacy rules. A file reference in a migrated row does not establish whether its new storage location is private.

Record which files are public, which are restricted, and who may download each restricted category. Test the download path directly, not only whether the attachment button appears. If the replacement uses temporary signed URLs, define their lifetime and how access changes affect already-issued links. A link can remain usable until its expiration even after the application stops issuing new ones.

How do you write an access model your team can test?

Write one decision record per meaningful combination of actor, resource and action. Include the relationship that grants access, the fields permitted in the result, and the evidence that proves the decision. Start with the most consequential data and expand until every exposed route has an owner and a policy.

Use this copyable record:

  • Resource and classification: what is being protected, and which fields or files are public or private?
  • Actor and context: anonymous visitor, member, owner, administrator or service; which organization and current membership state?
  • Action and entry point: list, search, read, create, edit, delete, export or download; which page, API or job invokes it?
  • Allow condition: the ownership, membership, role and resource-state checks required together.
  • Response and mutation limits: fields that may be returned or changed, and fields the server must derive itself.
  • Denial expectation: no protected content returned, no record changed and no external action triggered.
  • Evidence: test identity, synthetic record IDs, expected outcome, observed result, build identifier and reviewer.

Keep the expected policy independent from the implementation. If a test simply repeats the same mistaken condition as the code, both can agree and still be wrong. Have someone responsible for the product's permissions review the decision records before treating them as acceptance criteria.

An illustrative tenant-boundary test

Consider a fictional support portal with two organizations, North and South. Each has a ticket called DEMO-42 in its own test dataset. A North agent may read North tickets and edit their status. Only a North manager may export North tickets. Nobody in North may access South tickets. A North customer may read only tickets they created within North, excluding internal staff notes.

That gives you several distinct checks. The North agent can open the North ticket but cannot export it. A North customer can see the permitted fields on their own ticket but never the internal note, and cannot read another North customer’s ticket. A request using the South ticket's actual ID must fail even if it is submitted through the North interface. Changing the organization ID in an update request must not move the ticket into an unauthorized organization.

Finally, remove the agent's membership and repeat the protected requests according to the agreed revocation policy. State how quickly revocation must take effect. Include any session claims, authorization caches and download links in that decision. Information already downloaded cannot be recalled by changing a permission.

This is a test design example, not a client case or a claim about a completed migration.

Where should the replacement enforce permissions?

Enforce authorization on the server for every protected operation. The application needs to establish a trusted identity and apply the approved policy to the requested resource and action. Database controls can provide another enforcement layer; hidden buttons and client-side filters cannot replace these checks.

OWASP's authorization guidance recommends denying access by default and validating permissions on every request. Design the unrecognized role, missing membership and failed-policy-check cases deliberately. An error while checking access should not turn into permission to proceed.

If you use PostgreSQL row-level security, read its row security documentation before treating it as a safety net. RLS must be enabled. With RLS enabled and no applicable policy, normal access is denied, but superusers and BYPASSRLS roles bypass it, and table owners normally do too. Test through the database role the deployed application actually uses.

Row policies decide which rows operations can reach. They are not automatically a field-level response policy, a file-storage policy or authorization for an external side effect. Decide which layer handles each requirement and test the combined result. There is no universal “one Bubble rule equals one SQL policy” conversion.

For a hybrid Bubble migration, map both sides of the boundary. Decide which system owns membership changes and how the other learns about revocation. Otherwise, an employee removed in one system may retain access through the other.

What should block the migration from launching?

Block launch when a protected path has no agreed policy, a forbidden test returns private content or changes state, or the team cannot explain a privileged bypass. Passing happy-path tests is necessary but insufficient. Keep unresolved access failures visible instead of averaging them into a general test-pass percentage.

Run a focused acceptance pack against synthetic data in a restricted environment:

  • Allowed journeys: each supported role can complete its legitimate work with only the intended fields.
  • Other-user and other-organization access: direct IDs, list filters, searches, exports and downloads reject unauthorized access.
  • Write boundaries: create, edit and delete checks cover both the existing resource and the proposed new ownership or membership values.
  • Field boundaries: protected fields cannot be added to an update request or exposed through alternate responses, exports or filters.
  • Revocation: removal, suspension and role changes take effect within the agreed window across APIs, caches and file access.
  • Service paths: scheduled jobs and integration handlers have documented scope; an ordinary user cannot invoke their privileged behavior.
  • Failure behavior: missing identity, failed policy lookup and unexpected role values fail closed without protected side effects.

Capture more than the response status. A denied request should not leave an updated row, a queued email or a generated export behind it. Use sandbox integrations and test recipients so the acceptance run cannot contact real customers. Store sanitized evidence rather than credentials or private production payloads.

Retain these checks as regression tests, and name who maintains them when a new role, API or data type is added. The migration does not freeze the permission model forever.

What should you ask a migration team to deliver?

Ask for the approved access records, an inventory of enforcement points, allowed-and-denied test results, and a list of exceptions with accountable owners. Those artifacts let you review the rebuild's behavior. A statement that privacy rules were “ported” does not explain the coverage or the unresolved risks.

Bubble to Code's security review service covers authorization, data handling and migration boundaries. If you are scoping a rebuild, book a migration review and bring the roles, private data types and critical actions you need to preserve. Use that discussion to define the evidence required before cutover.

A checklist is a useful starting point, not a security certification. The right depth of review depends on the product's exposure and consequences of a failure.

Frequently asked questions

Can AI migrate Bubble privacy rules automatically?
Tools can help extract rules and propose code, but that does not establish equivalent authorization. Review the intended behavior, privileged paths and target configuration, then test allowed and denied operations. A clean import or a generated policy file is not an acceptance result.
Is PostgreSQL RLS enough on its own?
Not for the whole application. Correctly configured RLS can restrict row access, but you still need trusted identity handling, the right runtime database role, field and file controls, and authorization for business actions. Verify how these layers interact in the deployed architecture.
Do we need to rebuild the app to fix privacy problems?
No. If the problem is an incorrect Bubble rule or workflow condition, fixing and testing the current app may be the right next step. Migration becomes a separate decision about product requirements and ownership. It should not be used to postpone an access-control issue that needs attention now.

Sources

  1. 01Privacy-rule reference · Bubble Docs
  2. 02Privacy-rules guide · Bubble Docs
  3. 03Workflow API privacy documentation · Bubble Docs
  4. 04Data API privacy rules · Bubble Docs
  5. 05File guidance · Bubble Docs
  6. 06OWASP's authorization guidance · OWASP Cheat Sheet Series
  7. 07Row security documentation · PostgreSQL Docs

Keep reading

Bubble to Code is an independent service. Not affiliated with, endorsed by, or sponsored by Bubble Group, Inc.