In Salesforce, **security is not optional—it is architectural**. One of the most misunderstood (and misused) aspects of Apex development is **sharing context**. Many Salesforce implementations fail security audits, leak data, or behave unpredictably, not because of missing features, but because sharing rules were assumed rather than explicitly enforced.

At Winobell, we often encounter Salesforce orgs where Apex code unintentionally bypasses record visibility, leading to compliance risks, data exposure, and inconsistent user experiences. This article explains **how Apex sharing really works**, why defaults are dangerous, and what best practices enterprises should follow to build secure, future-proof Salesforce solutions.

### Understanding Apex Sharing Context: The Basics

By default, **all Apex classes run in without sharing mode** unless a sharing declaration is explicitly specified. This default behavior is powerful—but risky.

Sharing context in Apex controls **record-level access only**. It does **not** automatically enforce:

- Object-level permissions (CRUD)

- Field-level security (FLS)

These must always be handled explicitly using:

- Schema.sObjectType permission checks

- WITH SECURITY_ENFORCED in SOQL

- User-mode DML where applicable

Relying on defaults is one of the most common root causes of Salesforce security issues.

### Apex Sharing Keywords Explained

1. **with sharing**  
   - Enforces the organization’s sharing rules for the **current user**  
   - Users can only access records they are entitled to see  
   - Applies **record-level security only**  
   - Recommended for most user-facing business logic  
   **Best suited for:**  
   - UI controllers (LWC, Aura)  
   - Business services invoked by end users  
   - Data access layers where visibility matters

2. **without sharing**  
   - Ignores record-level sharing rules  
   - Allows access to **all records**, regardless of user visibility  
   - Still respects object permissions unless bypassed explicitly  
   **Best suited for:**  
   - System-level operations  
   - Background processing  
   - Administrative or data correction logic  
   ⚠️ Use sparingly. Overuse creates hidden security risks.

3. **inherited sharing**  
   - The class inherits the **sharing context of the calling code**  
   - Allows the same class to behave differently based on how it is invoked  
   - If no sharing is declared, Apex defaults to without sharing  
   **Best suited for:**  
   - Shared utility or service classes  
   - Logic reused across UI, batch, REST, and triggers  
   - Large enterprise orgs with layered architectures

### Apex Entry Points and Their Default Sharing Behavior

Different Apex entry points apply different default sharing contexts:

|     |     |
| --- | --- |
| **Apex Entry Point** | **Default Sharing** |
| Aura component controller | with sharing |
| @AuraEnabled method (LWC) | with sharing |
| Visualforce controller | without sharing |
| Apex REST service | without sharing |
| Asynchronous Apex (Batch, Queueable, Future, Scheduled) | without sharing |
| Other Apex entry points | without sharing |

Important: The calling context is only honored if the called class is declared as inherited sharing.

### Why Explicit Sharing Declaration Is Critical

When sharing is not declared:

- Code behavior becomes **unpredictable**
- Security issues surface only during audits or incidents
- Future enhancements can unintentionally expose data
- Salesforce security audit fails

Explicit sharing declarations:
- Make intent clear
- Improve maintainability
- Reduce regression risks
- Align code with Salesforce’s **Secure by Design** principles

### Winobell’s Recommendations

**For New Apex Classes**
Always declare sharing explicitly at creation time:
- **Default to with sharing**  
  - When unsure  
  - For user-driven operations
- **Use inherited sharing**  
  - For reusable service or utility classes  
  - When behavior should depend on the caller
- **Use without sharing**  
  - Only when business logic truly requires unrestricted access  
**Rule of thumb: If you must ask 'should this bypass sharing?'—it probably shouldn’t.**

**For Existing Apex Classes**
Introducing sharing into legacy code is **not risk-free**:
- Existing logic may rely on unrestricted access
- Automation and integrations may break
- Regression testing is mandatory
**Best approach:**
- Introduce sharing **incrementally**
- Apply during enhancements or refactoring
- Validate downstream automation, integrations, and reports

At Winobell, we often include this as part of a **Salesforce ROI Recovery or Security Hardening engagement**.

**Apex Triggers and Sharing: What Architects Must Know**
- **Triggers always run in without sharing by default**
- If a trigger calls an Apex class:
  - The class runs according to **its declared sharing**
- If a trigger fires due to a CRUD operation:
  - **User-mode DML (as user)** → trigger runs with sharing
  - **System-mode DML** → trigger runs without sharing
- If a trigger is invoked by a with sharing Apex class:
  - The trigger **inherits with sharing**

**Sharing vs Security: A Common Misconception (Sharing ≠ Security)**
To build secure Apex:
- Use with sharing or inherited sharing
- Enforce CRUD using Schema.describe
- Enforce FLS using WITH SECURITY_ENFORCED
- Prefer **user-mode DML and queries** where possible  
- Never assume UI-level security applies to Apex

### Final Thoughts

Salesforce provides powerful security tools—but it is up to architects and developers to use them correctly. The safest Apex code is **explicit, intentional, and defensive**.

At Winobell, we help organizations:
- Identify insecure Apex patterns
- Refactor legacy code safely
- Pass Salesforce security reviews
- Restore trust and ROI from underperforming Salesforce implementations

### Key takeaway:
_Never rely on defaults. Explicit sharing + explicit security enforcement leads to predictable, scalable, and compliant Salesforce solutions._

👉 _Talk to a Winobell Salesforce expert. Schedule a free 30-minute discovery call with our team by emailing us at_ [_support@winobell.com_](mailto:support@winobell.com) _or call us at_ +1 (437) 253-5469
