Data leak: Users with no access to a database can still read its relation and select fields

Hi! We ran into a field-level security behavior that looks like a data leak, and we’d like to understand whether it’s intended and whether a fix is planned.

Setup (simplified example)

A private Employee database. Fields: Name (text), Salary (number), Passport Number (text), Birth Date (date), Nationality (relation to a public Countries database), Gender (single-select), Fibery User (relation to the employee’s user).

User Bob is a workspace member with no access to Employee.

What Bob gets

Bob queries the Employee database directly (fibery.entity/query with q/from Employee; we saw it in a Custom App running as Bob). He receives all Employee records, with:

  • Name, Salary, Passport Number, Birth Date empty, as expected;
  • Nationality, Gender and the Fibery User link filled, and the same goes for any other relation, single-select or workflow field.

A q/count over Employee also returns the full number of records.

The data is not anonymous: the Fibery User link leads to a name every member can read, so Bob learns the nationality and gender of named colleagues.

(Every Employee record in our case is linked to a Fibery user, so we can’t tell whether Fibery returns the records because they are reachable from the Users database, or for any database.)

What we see in the schema

In fibery/meta of the fields, own primitive fields and text formulas have "fibery/secured?": true, while relations, single-selects and lookups have no fibery/secured? at all. As far as we can tell, there is no UI setting to change this.

Questions

  1. Is this intended?
  2. Are there plans to apply access rules to relation / single-select / lookup fields, or to hide the records of a database from users who have no access to it?
  3. Until then, what’s the recommended way to keep such data private? Our workaround idea is to store sensitive values as text fields instead of relations and selects, but that loses everything selects and relations give.

Thanks!

An update after more testing. It’s broader than one private database.

We created an API key for a test member and ran the same check against every database in our workspace (84):

  • fibery.entity/query (via /api/commands) returns all records of every database, including the ones the member has no access to: CRM, accounting, time tracking and so on. The number of rows matches the full record count.
  • It doesn’t depend on relations: records come back even from databases that have no relation fields at all, so nothing readable has to link to them.
  • In databases without access, the title and secured fields are empty, while relation, single-select and workflow fields are filled. So for any record you can see which company, deal, stage, owner etc. it is linked to.
  • q/count always returns the full number of records.

Interesting detail: Fibery AI, asked as the same test member, gets no rows for these databases (result: [] with hasNext: true). So Fibery does filter unreadable records somewhere, just not in the API that Custom Apps and integrations use. That makes it look like a bug rather than a design decision.

A correction to my first post: Bob doesn’t need any related database. Being a workspace member is enough.

Could someone from the team confirm whether this is a known issue and whether there’s a fix planned? Until then, any database whose relations or selects carry sensitive information is effectively readable by every member through the API.

Thanks for such a detailed reporting!

It’s a known issue, indeed. Some of the Fields in Fibery (such as fibery/id and Public ID) are not covered by permissions, meaning any User in a workspace regardless of their access can query them. As a consequence, any User can see how many records there are in every Database by simply querying IDs of all entities.

Moreover, since single- and multi-select options are public too, one can not only see how many Projects there are in total, but also check their distribution by State or Priority.

Additionally, if someone has partial access, they can find out even more, just like in your example.

We already have a solution designed that will close all such loopholes. I’ll provide an update in this topic as soon as the fix is out, but it’ll take some time. Sorry about the trouble!