Skip to content

Security and SOQL: Ensuring Data Security in Your Queries

Published 12/08/2025

SOQL Security Hero Image

In the world of Salesforce, data security is paramount. As a Salesforce administrator or developer, it’s crucial to understand how security settings impact your SOQL queries. This ensures that sensitive data is protected and that users only access information they are authorized to see. In this post, we’ll explore how to ensure data security when writing SOQL queries, focusing on field-level security, sharing rules, and their effects on query results.

Field-level security in Salesforce controls user access to individual fields within an object. This means that even if a user has access to a record, they might not have access to view or edit certain fields within that record.

Impact on SOQL Queries: When you run a SOQL query, Salesforce enforces field-level security. If a user does not have permission to view a field and the query explicitly requests that field, Salesforce may return a System.QueryException. This exception occurs because the query attempts to access a field that the user is not authorized to view. To prevent this, ensure that your queries only include fields the user has access to.

  • Check Field Accessibility: Before running a query, verify that the user has the necessary permissions to access the fields being queried. This can be done programmatically by checking field accessibility settings.
  • Use Dynamic SOQL: Consider using dynamic SOQL to construct queries at runtime based on the user’s permissions, including only the fields the user is authorized to access.
// Dynamic SOQL to include only accessible fields
String query = 'SELECT Name';
if (Schema.sObjectType.Employee.fields.Salary.isAccessible()) {
query += ', Salary';
}
query += ' FROM Employee WHERE Department = \'Finance\'';
List<Employee> employees = Database.query(query);
  • Leverage “WITH USER_MODE”: In Apex, Salesforce recommends using the WITH USER_MODE clause for enforcing field-level security (FLS) and object permissions. WITH USER_MODE provides comprehensive security checks, ensuring that the query respects all user permissions and security settings.
// Query with USER_MODE to enforce user permissions
List<Account> accounts = [SELECT Id, Name FROM Account WITH USER_MODE];
  • Use “WITH SECURITY_ENFORCED”: In Apex where WITH USER_MODE is not applicable, you can use the WITH SECURITY_ENFORCED clause in your SOQL queries to automatically enforce field- and object-level security. If any fields or objects referenced in the SOQL SELECT query using WITH SECURITY_ENFORCED are inaccessible to the user, a System.QueryException is thrown, and no data is returned.
// Query with SECURITY_ENFORCED to ensure security compliance
List<Contact> contacts = [SELECT Id, Email FROM Contact WITH SECURITY_ENFORCED];

By following these practices, you can ensure that your SOQL queries are secure and do not result in exceptions due to unauthorized field access.

Sharing rules in Salesforce determine the visibility of records based on user roles, groups, or territories. They are used to extend access to records beyond the default organization-wide sharing settings.

Impact on SOQL Queries: Sharing rules affect which records a user can see when running a SOQL query. If a user does not have access to a record due to sharing settings, that record will not appear in the query results. This ensures that users only see data they are authorized to access.

Understand the sharing model of your Salesforce organization. Use tools like the Salesforce Sharing Settings page to review and configure sharing rules. When writing queries, consider how sharing rules might impact the data returned for different users.

  • USER_MODE: When executing SOQL queries in USER_MODE, the queries respect the current user’s sharing rules and field-level security. This mode ensures that the query results are consistent with what the user is authorized to see based on their permissions and sharing settings.
  • SYSTEM_MODE: In SYSTEM_MODE, SOQL queries do not respect the user’s sharing rules, meaning they can access all records regardless of the user’s permissions. This mode is typically used in Apex classes marked as “without sharing,” allowing the code to bypass sharing rules. However, it is crucial to use this mode cautiously to avoid exposing sensitive data.

Using “With Sharing” and “Without Sharing” in Apex

Section titled “Using “With Sharing” and “Without Sharing” in Apex”

When writing Apex code that includes SOQL queries, you can specify whether the code should respect sharing rules using the “with sharing” or “without sharing” keywords.

  • With Sharing: This keyword ensures that the Apex code respects the sharing rules of the current user. Use “with sharing” when you want to enforce the same data visibility rules that apply to the user running the code.
public with sharing class AccountService {
public List<Account> getAccounts() {
return [SELECT Id, Name FROM Account];
}
}
  • Without Sharing: This keyword allows the Apex code to bypass sharing rules, potentially accessing records that the current user cannot see. Use “without sharing” cautiously, as it can expose sensitive data if not properly managed.
public without sharing class AccountService {
public List<Account> getAllAccounts() {
return [SELECT Id, Name FROM Account];
}
}

Interactions Between Sharing Settings and Execution Modes

Section titled “Interactions Between Sharing Settings and Execution Modes”
  • Apex Class “With Sharing” and Query in SYSTEM_MODE: Even if an Apex class is defined “with sharing,” if a query within that class is executed in SYSTEM_MODE, the query will bypass sharing rules and access all records. This can lead to unexpected data exposure if not carefully managed.
public with sharing class AccountService {
public void getAllAccounts() {
// This query will bypass sharing rules
List<Account> accounts = [SELECT Id, Name FROM Account WITH SYSTEM_MODE];
}
}
  • Apex Class “Without Sharing” and Query in USER_MODE: Conversely, if an Apex class is defined “without sharing,” but a query within that class is executed in USER_MODE, the query will still respect the user’s sharing rules and field-level security. This ensures that the query results are limited to what the user is authorized to see, despite the class’s broader access.
public without sharing class AccountService {
public void getUserAccessibleAccounts() {
// This query respects sharing rules
List<Account> accounts = [SELECT Id, Name FROM Account WITH USER_MODE];
}
}

By understanding how these settings and modes interact, you can design your Salesforce applications to maintain the appropriate level of data security and visibility, ensuring that sensitive information is protected while still allowing necessary access for business operations.

Field history tracking and auditing are essential for monitoring changes to sensitive data and ensuring compliance with data governance policies.

  • Impact on SOQL Queries: While field history tracking does not directly affect SOQL queries, it provides a valuable audit trail of changes to critical fields. Use SOQL queries to access field history data and generate reports on data changes over time.
// Query to retrieve field history data
List<OpportunityFieldHistory> history = [SELECT OldValue, NewValue, CreatedDate FROM OpportunityFieldHistory WHERE Field = 'StageName'];

Ensuring data security in SOQL queries is a critical responsibility for Salesforce administrators and developers. By understanding and applying field-level security, sharing rules, and Apex sharing settings, you can protect sensitive data and ensure that users only access information they are authorized to see. By mastering these security concepts, you can create robust and secure Salesforce applications that meet your organization’s data protection requirements.