UI Security: SOQL Injection Prevention
SOQL Injection is a critical security vulnerability in Salesforce development where malicious users can manipulate SOQL queries by injecting unauthorized query fragments through user-supplied input. As a Platform Developer I, understanding and preventing SOQL injection is essential for building sec… SOQL Injection is a critical security vulnerability in Salesforce development where malicious users can manipulate SOQL queries by injecting unauthorized query fragments through user-supplied input. As a Platform Developer I, understanding and preventing SOQL injection is essential for building secure applications. **How SOQL Injection Occurs:** When developers dynamically construct SOQL queries by concatenating user input directly into query strings, attackers can alter the query's logic. For example: ```apex String userInput = 'test\' OR Name LIKE \'%'; String query = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\''; ``` This could expose unauthorized records by modifying the WHERE clause. **Prevention Techniques:** 1. **Static SOQL (Inline SOQL):** The most effective prevention is using static SOQL with bind variables. Variables are automatically escaped and treated as data, not executable code: ```apex String searchTerm = userInput; List<Account> accounts = [SELECT Id FROM Account WHERE Name = :searchTerm]; ``` 2. **String.escapeSingleQuotes():** When dynamic SOQL is necessary, use this built-in method to escape single quotes in user input: ```apex String sanitized = String.escapeSingleQuotes(userInput); String query = 'SELECT Id FROM Account WHERE Name = \'' + sanitized + '\''; ``` 3. **Typecasting:** For numeric or date inputs, cast values to their appropriate types (Integer, Date, etc.) before incorporating them into queries, ensuring non-string data cannot be manipulated. 4. **Whitelisting:** Validate user input against a predefined set of acceptable values, especially for field names or object names used in dynamic queries. 5. **WITH SECURITY_ENFORCED:** Add this clause to enforce field-level and object-level security, providing an additional layer of protection. **Best Practices:** - Always prefer static SOQL over dynamic SOQL - Never trust user input directly - Use bind variables whenever possible - Apply escapeSingleQuotes() for all dynamic query string concatenations - Implement proper CRUD/FLS checks alongside injection prevention These techniques ensure your Salesforce applications remain secure against unauthorized data access through SOQL injection attacks.
UI Security: SOQL Injection Prevention – Complete Guide for Salesforce Platform Developer 1
Why SOQL Injection Prevention Matters
SOQL injection is one of the most critical security vulnerabilities in the Salesforce ecosystem. It occurs when user-supplied input is directly concatenated into a SOQL query string without proper sanitization. An attacker can manipulate the query logic, potentially accessing unauthorized data, bypassing sharing rules, or extracting sensitive records they should never see. Because Salesforce applications frequently build dynamic queries based on user input (search fields, filters, URL parameters), understanding and preventing SOQL injection is essential for every Platform Developer.
For the Salesforce Platform Developer 1 (PD1) exam, SOQL injection prevention falls under the User Interface and security domains. Salesforce expects developers to know not only what SOQL injection is but also how to prevent it using platform-provided tools.
What Is SOQL Injection?
SOQL injection is a code-level vulnerability where an attacker inserts or "injects" malicious SOQL fragments into a query by manipulating input that is dynamically incorporated into a query string. It is conceptually similar to SQL injection in traditional web applications, but it targets Salesforce Object Query Language (SOQL).
Example of Vulnerable Code:
String userInput = ApexPages.currentPage().getParameters().get('name');
String query = 'SELECT Id, Name FROM Account WHERE Name = \'' + userInput + '\'';
List<Account> results = Database.query(query);
If a user enters a value like: ' OR Name != '
The resulting query becomes:
SELECT Id, Name FROM Account WHERE Name = '' OR Name != ''
This would return all Account records, completely bypassing the intended filter. More sophisticated attacks could reveal data from other fields or objects depending on query structure.
How SOQL Injection Works – Step by Step
1. User Input Entry Point: The application accepts input from users through Visualforce pages, Lightning components, URL parameters, or form fields.
2. Dynamic Query Construction: The developer builds a SOQL query string by concatenating user input directly into the query without sanitization.
3. Malicious Payload: An attacker crafts special input that alters the query's logic (e.g., closing a string literal with a single quote and appending additional SOQL clauses).
4. Query Execution: The manipulated query runs via Database.query(), returning unintended results or exposing sensitive data.
Prevention Techniques
Salesforce provides several mechanisms to prevent SOQL injection. You must know all of these for the exam:
1. Static SOQL (Inline SOQL) – The Best Defense
Use static SOQL with bind variables whenever possible. Bind variables are automatically escaped by the platform and are immune to injection.
String userInput = ApexPages.currentPage().getParameters().get('name');
List<Account> results = [SELECT Id, Name FROM Account WHERE Name = :userInput];
The :userInput bind variable ensures the value is treated as a literal value, not as executable SOQL. This is the preferred and simplest approach.
2. String.escapeSingleQuotes()
When you must use dynamic SOQL (Database.query()), use String.escapeSingleQuotes() to escape any single quotes in user input. This prevents attackers from breaking out of string literals.
String userInput = String.escapeSingleQuotes(ApexPages.currentPage().getParameters().get('name'));
String query = 'SELECT Id, Name FROM Account WHERE Name = \'' + userInput + '\'';
List<Account> results = Database.query(query);
This method adds a backslash before each single quote, neutralizing the injection attempt.
3. Type Casting / Whitelisting
For non-string inputs (like numbers or IDs), cast them to the expected type. If the input is supposed to be an integer, convert it to an Integer. If it should be an Id, cast it to an Id type. Invalid input will throw an exception rather than being injected.
Integer maxRecords = Integer.valueOf(ApexPages.currentPage().getParameters().get('limit'));
For fields or object names from user input, validate against a whitelist of allowed values rather than inserting them directly.
4. Use Visualforce <apex:param> and Proper Encoding
When passing parameters in Visualforce, use built-in tags like <apex:param> rather than raw URL concatenation. Also leverage output encoding attributes such as escape="true" (the default for <apex:outputText>).
5. WITH SECURITY_ENFORCED / stripInaccessible()
While these are more about field-level and object-level security enforcement than injection prevention, they add defense-in-depth by ensuring queries respect the running user's permissions. They may appear on the exam in the broader context of UI security.
Key Concepts to Remember
• Static SOQL with bind variables is inherently safe from SOQL injection – always prefer it.
• Dynamic SOQL (Database.query()) is where SOQL injection risk exists.
• String.escapeSingleQuotes() is the primary defense for dynamic SOQL when bind variables cannot be used.
• SOQL injection can affect WHERE clauses, ORDER BY clauses, LIMIT clauses, and any part of a dynamically built query.
• Unlike SQL injection, SOQL injection cannot perform DML operations (INSERT, UPDATE, DELETE) because SOQL is read-only. However, it can still lead to unauthorized data access, which is a serious security breach.
• Bind variables cannot be used for field names, object names, or clauses like ORDER BY in dynamic SOQL – only for values in WHERE conditions. For these other parts, you need whitelisting.
Common Exam Scenario Patterns
The exam often presents code snippets and asks you to identify the secure or insecure approach:
Scenario A: Code uses Database.query('SELECT ... WHERE Name = \'' + input + '\'') without escapeSingleQuotes. This is vulnerable.
Scenario B: Code uses [SELECT ... WHERE Name = :input]. This is safe.
Scenario C: Code uses String.escapeSingleQuotes(input) before concatenation in Database.query(). This is safe for string values.
Scenario D: Code takes a field name from user input and inserts it into ORDER BY without validation. This is vulnerable – escapeSingleQuotes won't help because field names aren't inside quotes.
Exam Tips: Answering Questions on UI Security – SOQL Injection Prevention
1. Default to bind variables: If the question asks for the "best" or "recommended" way to prevent SOQL injection, the answer is almost always to use static SOQL with bind variables (:variableName). Choose this option first if available.
2. Know when dynamic SOQL is required: Bind variables cannot substitute field names, object names, or entire clauses. Recognize scenarios where dynamic SOQL is genuinely necessary (e.g., user-selected sort fields or dynamically chosen objects).
3. String.escapeSingleQuotes() is for dynamic SOQL only: If the question involves Database.query() and user input in a WHERE clause string value, look for String.escapeSingleQuotes() as the correct answer.
4. Read code carefully: Exam questions may show subtle differences between safe and unsafe patterns. Look for whether user input is being concatenated directly or going through a bind variable or escape function.
5. Remember the limitations: escapeSingleQuotes protects string literals but does NOT protect against injection in non-string contexts (like ORDER BY field names or numeric values). For those, type casting or whitelisting is required.
6. Eliminate obviously wrong answers: Options suggesting SOQL injection can perform DML, or options that rely solely on profile permissions to prevent injection, are incorrect. Injection is a code-level issue requiring code-level fixes.
7. Watch for the WITH SECURITY_ENFORCED distractor: This enforces FLS/object permissions but does NOT prevent SOQL injection. Don't confuse data access security with injection prevention.
8. Dynamic SOSL is also vulnerable: The same principles apply to dynamic SOSL queries built with Search.query(). Be aware that injection prevention applies to both SOQL and SOSL.
9. Practice identifying patterns: Before the exam, review multiple code examples and practice spotting whether a query is static or dynamic, whether user input is escaped, and where the injection point exists.
10. Think defense-in-depth: The best answers often combine multiple strategies – using bind variables where possible, escapeSingleQuotes for dynamic string values, type casting for non-strings, and whitelisting for field/object names.
Summary
SOQL injection prevention is a high-priority topic for the PD1 exam. Remember the golden rule: use static SOQL with bind variables whenever possible. When dynamic SOQL is unavoidable, always sanitize input using String.escapeSingleQuotes() for string values and type casting or whitelisting for non-string elements. Understanding these patterns will help you confidently answer exam questions on this critical security topic.
🎓 Unlock Premium Access
Salesforce Certified Platform Developer I + ALL Certifications
- 🎓 Access to ALL Certifications: Study for any certification on our platform with one subscription
- 2750 Superior-grade Salesforce Certified Platform Developer I practice questions
- Unlimited practice tests across all certifications
- Detailed explanations for every question
- PD1: 5 full exams plus all other certification exams
- 100% Satisfaction Guaranteed: Full refund if unsatisfied
- Risk-Free: 7-day free trial with all premium features!