- Home
- /
- Salesforce Testing
- /
- Security Testing
- /
- Negative Access Testing
Salesforce Negative Access Testing
Salesforce negative access testing asserts the deny cases: it deliberately attempts the actions, records and fields each persona should not reach and passes only when access is correctly blocked. It proves the half of every access requirement that functional testing ignores — the and-nothing-more part — so over-provisioning fails a test on the day it is introduced instead of surfacing later in an audit or incident.
Negative access testing is a method that applies across every access layer, rather than a single Salesforce feature.
What negative access testing is
Most Salesforce testing is positive: can the sales rep create the opportunity, can the agent close the case, can the partner register a deal. Those tests fail loudly when access is too tight, because legitimate work breaks. Nothing equivalent happens when access is too loose. A rep who can also see compensation fields, or an agent who can also edit another region's accounts, gets no error — the extra access simply works.
Negative access testing closes that gap by writing tests whose expected result is a block. For each persona, it lists the objects, fields, records, system permissions and actions that must be denied, attempts each one, and treats success as a failure. Because Salesforce access is additive across profiles, permission sets and permission set groups, and record visibility is additive across ownership, role hierarchy and sharing, a deny assertion is the only direct evidence that no layer is granting more than intended.
This page covers the method itself: how to choose deny cases, how to tell a genuine block from a broken test, and how to keep the suite honest. Layer-specific guides apply it to field-level security, sharing rules, restriction rules and integration users.
Why deny cases go untested
The reasons are structural, which is why negative access testing has to be planned rather than hoped for.
Requirements describe what users do
User stories specify what a persona needs. What it must not do is implied, so it never becomes an acceptance criterion or a test.
Testers run as admins
Tests executed under an administrator or a tester's broad profile succeed on everything, making deny cases impossible to observe.
The UI hides the evidence
A missing button or tab looks like a block, but the same action may still succeed through a URL, list view, API call or Apex method.
Over-provisioning is silent
An unauthorized action that succeeds creates no error, no log entry anyone reviews and no user complaint.
Test data belongs to the tester
When the persona owns every test record, sharing boundaries are never exercised because nothing belongs to anyone else.
Additive grants hide the source
When one of many permission sets widens access, reviewing any single set looks correct, and only the combined behavior reveals the issue.
Deny attempts and the signal that proves a block
A good deny assertion checks for the right kind of block, not just for any failure. Exact messages vary by surface and API version, so assertions should match on the access category rather than exact wording.
| Layer | Deny attempt | Signal that access is correctly blocked |
|---|---|---|
| Object create or delete | Insert or delete a record on an object the persona only reads | Insufficient access response, and no record created or removed |
| Object read | Query or open an object with no read permission | Object is reported as not accessible or not supported for the user |
| Field read | Select a field without read access through the API | Invalid field or no such column response for that field |
| Field edit | Update a read-only field inline or through the API | Update rejected, and the stored value unchanged afterward |
| Record visibility | Open or query a record owned outside the persona's sharing scope | Record absent from query results or an insufficient privileges page |
| Record edit | Edit a record the persona can see but not edit | Insufficient access or read-only response, value unchanged |
| System permission | Export a report, manage users or view setup without the permission | Action unavailable and the equivalent API call rejected |
| Apex and flows | Invoke a class or flow not enabled for the persona | No access to the class, page or flow, and no data returned |
Designing a deny suite
A deny suite is built from the intended-access baseline, not invented test by test.
Start from the intended-access baseline
For each persona, take the documented allowed access and derive the complement: sensitive objects, fields, records and permissions that must be denied.
Prioritize by impact
Rank deny cases by what exposure would cost — PII, financial data, other customers' records, administrative rights — and test the highest first.
Pair every deny with a positive
For each blocked action, keep a positive control that proves the persona and data are valid, so a block means a boundary rather than a broken setup.
Attempt through more than one surface
Try the denied action in the user interface and through the API or a direct URL, because enforcement in one does not prove the other.
Assert both the response and the state
Check that the attempt was rejected and that data afterward is unchanged, so a partial write behind an error is still caught.
Verify the tests can fail
In a sandbox, deliberately grant a denied permission and confirm the related deny test turns red before trusting the suite.
Test data rules for negative access testing
Deny cases are only meaningful when the data gives each persona something it could wrongly reach.
- Seed sentinel records owned by users outside every test persona's role, territory, team or account.
- Give sentinel records distinctive values so any leak is unmistakable in results and evidence.
- Populate sensitive fields on every seeded record, because an empty field cannot prove it was hidden.
- Include records that sit just outside sharing rule, restriction rule and sharing set criteria, not only obviously unrelated ones.
- Create test personas with the same profile, permission set and group assignments as real users, never with a tester's own access.
- Reset or reserve seeded records between runs so a previous test's edits do not change what the next deny case can reach, using test data reset.
Blocked versus broken
The biggest risk in negative access testing is a false pass. A test expecting an error will happily pass when the persona cannot log in, when a permission set license is missing, when the record ID is wrong, or when the org is down. Each of those produces a failure that looks exactly like a correct denial, and a suite full of them reports perfect least privilege while proving nothing.
Three practices prevent this. First, the paired positive control: the same persona must succeed at a legitimate action in the same run, and the denied record must be proven to exist by a privileged check. Second, match the category of the failure — an access response rather than a login, license or not-found error. Third, test the tests: periodically widen access on purpose in a sandbox and confirm the matching deny assertions fail. A deny test that has never been seen to fail should not be trusted as evidence.
Negative access scenarios across personas
A cross-section of deny cases that together exercise every access layer.
| Scenario | What it proves |
|---|---|
| Sales rep opens a peer's opportunity in the same role by record ID | Private sharing holds between peers |
| Service agent exports a case report with 50,000 rows | Export Reports is not granted to agents |
| Marketing user updates Account.OwnerId through the API | Transfer rights are absent even where edit is allowed |
| Partner user queries internal discount fields on a shared quote | Field-level security blocks partner reads |
| Finance approver creates the invoice they will approve | Conflicting capabilities are not combined, as covered in segregation of duties |
| Integration user calls a metadata deploy | Data integrations cannot change configuration |
| Guest visitor requests an internal case by ID | Public site access excludes internal records |
Evidence and what SyntraFlow is designed to do
These capabilities are available for demonstration and proof-of-concept validation.
Deny assertions as first-class tests
SyntraFlow is designed to treat a correct block as the expected result, so least privilege is expressed as passing tests.
Paired positive controls
Deny scenarios can be configured with a companion positive check, reducing false passes from broken personas or missing data.
Auditor-ready deny evidence
Each run can retain persona, attempted action, expected block and observed outcome, showing reviewers what was proven to be denied.
Regression on every change
The deny suite can re-run after deployments and seasonal releases as part of security regression testing.
Related pages
Salesforce security testing
The hub that frames positive and negative access validation across every layer.
Field-level security testing
Applies deny assertions to hidden and read-only fields on every surface.
Sharing rule testing
Applies deny cases to records outside each persona's sharing scope.
Segregation of duties
Tests that conflicting capabilities are denied in combination.
Security regression testing
Keeps the deny suite running after every change and release.
Synthetic test data
Generates the sentinel records deny cases need without using production data.
Negative Access Testing testing FAQs
What is Salesforce negative access testing?
It is testing that deliberately attempts actions a persona should not be able to perform — reading a hidden field, editing another team's record, using an administrative permission — and passes only when Salesforce blocks the attempt. It proves least privilege directly rather than inferring it from configuration.
Why is negative access testing necessary if positive tests pass?
Positive tests only detect access that is too narrow. Access that is too broad produces no error, so every positive test still passes. Deny assertions are the only tests that fail when a profile, permission set, group or sharing rule grants more than intended.
How do you avoid false passes in deny tests?
Pair each deny assertion with a positive control for the same persona, confirm the target record exists through a privileged check, and match on an access-denied category rather than any error. Periodically widen access in a sandbox to confirm the deny tests actually fail.
Is checking that a button is hidden a valid negative test?
It is a useful user experience check but not proof of a block. The same action may still be possible through a direct URL, list view, API or Apex method. A negative access test should attempt the underlying operation and confirm the data is unchanged.
How many deny cases does a persona need?
Start with the highest-impact exposures for each persona — sensitive fields, other teams' or customers' records, delete and export rights, and administrative permissions. Most teams find a focused set per persona gives strong coverage, then extend it as new objects and fields are added.
How does negative access testing relate to penetration testing?
Penetration testing looks for exploitable vulnerabilities, often from outside. Negative access testing verifies that your configured access model denies what it should for known personas, and is designed to run repeatedly as a regression suite. The two complement each other rather than overlap.
Make over-provisioning fail a test, not an audit
See how negative access testing turns least privilege into a suite you can re-run on every release.