All insights

Platform

Restriction and scoping rules in Salesforce: the two sharing controls most orgs skip

Org-wide defaults and sharing rules decide who can open a record. Restriction rules take access back that sharing already granted, and scoping rules only change what shows up by default. What each one does, the limits that catch people (standard objects, EQUALS-only criteria, system-mode Apex), and what your Agentforce agent actually inherits.

Most Salesforce sharing problems get solved by giving people more access. You open an org-wide default, add a sharing rule, drop someone into a role. Restriction rules solve the opposite problem.

A user already has access to a record through sharing, and you need to take it away for a subset of records without touching the model that granted it. That’s a different tool, and a lot of orgs build a convoluted sharing-rule workaround because they’ve never used it.

The one-line version I give people: restriction rules permanently narrow what a user can access, on top of whatever sharing allowed. Scoping rules don’t change access at all. They only change which records show up by default.

Confuse the two and you’ll either leak data you thought you’d hidden, or hide records your users can still reach in one click. This post is what each one does, the limits that decide whether you can use them, and what an Agentforce agent inherits when it reads your data.

Access is additive until a restriction rule says otherwise

Start with how record access is computed, because restriction rules only make sense as the last step. Access is built from the bottom up. The object’s org-wide default sets the floor, then the role hierarchy, sharing rules, teams, manual shares, and territories each add access on top.

Everything in that stack grants. Nothing in it takes away. The most permissive grant wins, which is why sharing is so easy to open and so hard to close.

A restriction rule is the one mechanism that subtracts. After sharing has decided a user can see a set of records, the restriction rule filters that set down to only the records matching its criteria. Salesforce’s documentation frames it this way: the records a user can already access through sharing are further limited to those that meet the rule’s record filter.

The classic case is two sales teams who shouldn’t see each other’s activity, or a confidential matter only a named group should reach, sitting inside an object everyone otherwise shares.

The “permanent” part matters. A list-view filter or a scoping rule changes a default the user can switch off. A restriction rule can’t be. If the record doesn’t match the rule, the user can’t reach it from a list view, a report, a lookup, a related list, search, SOQL, or SOSL. It’s gone from their view of that object.

Where restriction rules are enforced, and the one place they aren’t

A restriction rule applies everywhere a user reads records in their own context: list views, lookups, related lists, reports, global search, SOQL, and SOSL all honor it. A restricted record still appears in Recent Items as a stub, but the user can’t open it. That breadth is the point. Unlike a list-view filter, there’s no surface where the hidden records slip back into view.

The exception is the one you have to design around. Code running in system mode is exempt. A restriction rule narrows access for the running user, so anything that runs without a user’s sharing context ignores it.

An Apex class declared without sharing, or any operation in system mode, reads the full set as if the rule weren’t there. That’s not a bug. It’s the definition of system mode. But it means a restriction rule is a user-access control, not a hard data boundary.

If your real requirement is “this data must never be readable by this code path,” a restriction rule is the wrong layer. Field-level security or a separate object is the right one. Restriction rules sit alongside object permissions and FLS. They don’t override either, and they don’t replace them.

The limits that decide whether you can use them at all

Restriction rules are narrower than people expect, and the limits are where most plans die.

The supported-object list is the first wall. As of the current release, restriction rules are available on custom objects, external objects (built on the OData 2.0, OData 4.0, or Cross-Org adapters), events, tasks, contracts, quotes, time sheets, and time sheet entries. The big standard objects, Account, Contact, Opportunity, Lead, Case, are not on that list.

So if your requirement is “hide some Accounts from some users,” restriction rules don’t do it, and you’re back to the sharing model or a redesign. Check the object in Object Manager before you promise anyone a restriction rule. The list has grown over releases and will keep changing.

The count limit is next. Enterprise and Developer editions allow up to two active restriction rules per object. Performance and Unlimited editions allow up to five. Those are active-rule caps, so plan your scenarios around a handful.

The criteria limit is the one that bites in practice. The record filter supports the EQUALS operator only. No AND/OR between conditions, no greater-than, no formula fields. You get “field equals value,” and the value can reference the running user, but the logic is deliberately simple. Richer conditions have to be modeled into a single field you can match on equality, which often means a flag field maintained by a flow or trigger.

A quiet gotcha closes it out. Salesforce recommends configuring your rules so only one active restriction or scoping rule applies to a given user per object, but it doesn’t enforce that. If two active rules both match a user, only one is honored, and which one is not something to leave to chance. Design so a user ever matches exactly one.

Scoping rules change the view, not the access

Scoping rules look similar in Setup and do something completely different. A scoping rule sets which records a user sees by default, without changing what they’re allowed to see. It’s a default filter, not a boundary.

Turn one on and a user’s list views, reports (when “Filter by scope” is selected), and SOQL queries return the scoped subset by default. But the user can switch the scope, change the list-view filter, or run a query that ignores it, and every record they have access to is still reachable.

Scoping rules are available for custom objects and standard objects including Account, Case, Contact, Lead, and Opportunity, and they can be toggled query by query. In SOQL you opt in or out with the USING SCOPE clause, which makes the intent explicit in the query itself.

So the decision between the two is really a decision about trust. If a user merely shouldn’t be bothered with records outside their patch, but it’s fine if they look, that’s a scoping rule, and it makes their day cleaner. If a user must not be able to reach those records, that’s a restriction rule, and nothing less will hold.

Reaching for a scoping rule when you needed a restriction rule is how data you believed was hidden turns out to be one filter change away.

Both are metadata, RestrictionRule and ScopingRule, so they deploy through your normal pipeline and belong in source control with the rest of your security configuration, not clicked together by hand in production.

What your Agentforce agent inherits

This is where the two rules stop being admin trivia. An Agentforce agent reads and writes data as a specific running user, with that user’s profile, permission sets, and sharing. Every security review should ask whether the agent respects the same record boundaries a person would. Restriction rules are a sharp test of it.

When the agent reads through a path that runs in the user’s context, a standard “get records” action, a report, a SOQL query in user mode, the restriction rules on that user apply. The agent sees exactly the narrowed set the person would. That’s the behavior you want, and it’s the argument for making the agent’s running user a real, scoped user rather than an over-powered one.

The catch is the system-mode exemption from earlier. A custom Apex action declared without sharing, or any action that reaches data in system mode, bypasses restriction rules entirely. Build an action that queries in system mode and it can hand the model records the running user is restricted out of, and the model will summarize them back to the customer.

The restriction rule did its job on the user. The action went around the user. If you’re grounding an agent on data where a restriction rule is the boundary, every custom action in its path needs to enforce sharing, and you need to confirm it, because the default for Apex is the wrong one here.

The broader version of this, making sure an agent only ever sees what the user is allowed to, is the whole point of Data 360 governance for agent access. Restriction rules are the core-CRM half of it.

What I’d check this week

Three quick audits catch most of the trouble.

First, list the objects where you’ve built a sharing-rule maze to remove access, and check whether a restriction rule would do it in one declarative step, assuming the object supports them.

Second, anywhere you’ve used a scoping rule to hide sensitive records, confirm you didn’t actually need a restriction rule. A scoping rule is a suggestion, not a lock.

Third, if you’ve got an agent live, trace every action in its topics and confirm the ones hitting restricted objects run in the user’s sharing context, not system mode. The first two keep your sharing model trustworthy. The third keeps the agent from undoing it.

Understanding the basics

What’s the difference between a restriction rule and a scoping rule?

A restriction rule permanently narrows what a user can access, taking back records that sharing already granted; the excluded records are unreachable everywhere, including reports and SOQL. A scoping rule only changes which records show by default and doesn’t limit access, so the user can switch scope and still reach everything their sharing allows.

Do restriction rules work on standard objects like Account and Opportunity?

Not for the main standard objects. As of the current release they’re supported on custom objects, external objects (OData 2.0, OData 4.0, Cross-Org adapters), events, tasks, contracts, quotes, time sheets, and time sheet entries. Account, Contact, Opportunity, Lead, and Case are not supported, so confirm the object in Object Manager, since Salesforce has expanded the list over time.

Does an Agentforce agent respect restriction rules?

It depends on how the agent reaches the data. When it reads in the running user’s context (a standard get-records action, a report, a user-mode SOQL query), the user’s restriction rules apply and the agent sees only the narrowed set. A custom Apex action running in system mode, including any class declared without sharing, bypasses them, so every custom action in the agent’s path must enforce sharing if a restriction rule is your boundary.

Why does my restriction rule only allow EQUALS?

The record filter is intentionally simple: EQUALS only, with no AND/OR logic and no formula fields. To match on richer conditions, model the logic into a single field (often a flag maintained by a flow or trigger) and have the rule match on equality. You also get a small number of active rules per object, two in Enterprise and Developer editions, five in Performance and Unlimited.


Record-level security is the layer an AI agent is most likely to undermine without anyone noticing, and the hardest to retrofit once an agent is live. If you want your sharing model audited before it grounds an agent, talk to us. Getting access right before the agent reads a single record is what keeps a pilot from becoming an incident.

Keep reading

All insights