The Record Field That Leaked Salary Data
An HR application stores employee records in a record type backed by a database view. The view joins employee, department, and compensation tables. A single group, HR Users, has reader access to the record type. The team recently added a Salary field to the view and to the record type so managers could see it on a dashboard. Shortly after, a manager reported seeing a peer's salary on a related-record grid. Investigation shows the dashboard's related record uses the same record type, and access is enforced only at the record-type level. There is no field-level security configured. The compliance team requires that only users in a Compensation Admins group see salary values, and that all other users see the record but not the field.
1. Explain the exposure and recommend where access control must be enforced.
Read the worked answer
Record-level security on the record type grants read access to the whole row, including the Salary field, to every member of HR Users. Because the related-record grid and dashboard both resolve through the same record type, any user who can see the record can see every field the view returns. There is no field-level masking, so adding the column to the view was effectively a data disclosure.
The fix must happen at the data layer, not just the UI:
- Remove
Salaryfrom the shared view. Create a separate view (or a separate record type) that includes salary, with its own security. - Grant that salary view/record type only to
Compensation Admins. - In the UI, show salary components only to
Compensation Adminsvia a visibility condition - but treat the UI condition as defense in depth, not the control. - Verify the related-record grid uses the non-salary record type.
Masking in the interface alone is insufficient: a user with record read access can still surface the field through exports, reports, or a saved query unless the underlying data object does not expose it.
2. A manager argues they need to see their direct reports' salaries, not just Compensation Admins. How would you model this without reopening the leak?
Read the worked answer
Introduce a contextual access rule rather than broadening the group:
- Keep the salary-bearing record type restricted.
- Add a record-level security expression that grants read on the salary record when
loggedInUseris the record's manager of record (e.g.,record.managerId = loggedInUser). - Combine with a
Compensation Adminsgroup rule using OR so admins still see everything. - Ensure the manager-of-record relationship is maintained by data, not by a hardcoded list.
Test the edges explicitly: a manager viewing a peer's record (should be denied), a manager viewing a former report after a reorg (should be denied once the relationship is updated), and an admin viewing any record (allowed). Document that this is a row-level grant on a sensitive object, and confirm exports and any related grids inherit the same rule. If the org cannot accept manager-level access, the fallback is a request workflow that surfaces salary through a controlled, audited task instead of direct record read.