Security 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.

LayerDeny attemptSignal that access is correctly blocked
Object create or deleteInsert or delete a record on an object the persona only readsInsufficient access response, and no record created or removed
Object readQuery or open an object with no read permissionObject is reported as not accessible or not supported for the user
Field readSelect a field without read access through the APIInvalid field or no such column response for that field
Field editUpdate a read-only field inline or through the APIUpdate rejected, and the stored value unchanged afterward
Record visibilityOpen or query a record owned outside the persona's sharing scopeRecord absent from query results or an insufficient privileges page
Record editEdit a record the persona can see but not editInsufficient access or read-only response, value unchanged
System permissionExport a report, manage users or view setup without the permissionAction unavailable and the equivalent API call rejected
Apex and flowsInvoke a class or flow not enabled for the personaNo 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.

1

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.

2

Prioritize by impact

Rank deny cases by what exposure would cost — PII, financial data, other customers' records, administrative rights — and test the highest first.

3

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.

4

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.

5

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.

6

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.

ScenarioWhat it proves
Sales rep opens a peer's opportunity in the same role by record IDPrivate sharing holds between peers
Service agent exports a case report with 50,000 rowsExport Reports is not granted to agents
Marketing user updates Account.OwnerId through the APITransfer rights are absent even where edit is allowed
Partner user queries internal discount fields on a shared quoteField-level security blocks partner reads
Finance approver creates the invoice they will approveConflicting capabilities are not combined, as covered in segregation of duties
Integration user calls a metadata deployData integrations cannot change configuration
Guest visitor requests an internal case by IDPublic 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.