SOQL Injection
By the end of this lesson, you'll be able to:
- Recognize a SOQL injection vulnerability in dynamic SOQL
- Apply bind variables and escapeSingleQuotes() as the two core defenses
- Explain why this deserves a full lesson beyond Module 20's introduction
Prerequisites: "User Mode Database Operations"
A recap, viewed through a security lens
// DANGEROUS
String userInput = someFormField;
String queryString = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';
List<Account> accounts = Database.query(queryString);
// DANGEROUS— the label says it all.String userInput = someFormField;— raw, unescaped user input.String queryString = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';— concatenated directly into the query text.List<Account> accounts = Database.query(queryString);— runs the built string.
Warning: Module 20 introduced this exact danger — concatenating raw user input directly into a dynamic query string on line 3 lets a carefully crafted input alter the query's actual structure, potentially exposing or affecting data the input was never meant to touch.
Defense 1: bind variables (the default choice)
String userInput = someFormField;
List<Account> accounts = Database.query('SELECT Id FROM Account WHERE Name = :userInput');
String userInput = someFormField;— the same raw input.List<Account> accounts = Database.query('SELECT Id FROM Account WHERE Name = :userInput');— a bind variable never mixes raw input with the query's syntax at all — exactly Module 20's recommendation, restated as this module's primary defense.
This is the preferred fix whenever the query's overall structure doesn't need to change based on user input — just a value being filtered on.
Defense 2: escaping, when structure genuinely must vary
String fieldName = getFieldNameFromConfig(); // the field itself varies, not just a value
String safeFieldName = String.escapeSingleQuotes(fieldName);
String queryString = 'SELECT Id FROM Account WHERE ' + safeFieldName + ' != null';
String fieldName = getFieldNameFromConfig();— bind variables can only stand in for values, not query structure like field or object names — here, the field itself varies.String safeFieldName = String.escapeSingleQuotes(fieldName);—String.escapeSingleQuotes()neutralizes quote characters that could otherwise let an input break out of the intended structure.String queryString = 'SELECT Id FROM Account WHERE ' + safeFieldName + ' != null';— now safe to concatenate.
This is a narrower, last-resort tool compared to bind variables, not a general substitute for them.
Why this earns a dedicated security-module lesson
Module 20 introduced SOQL injection as one lesson among many on writing correct SOQL; this security module revisits it specifically as a security vulnerability class, alongside CRUD/FLS and sharing — the same underlying risk, but now framed as something to actively defend against as a matter of course, on every dynamic query written, not just something to remember once.
Exercise
Rewrite this dynamic query to use a bind variable instead of string concatenation.
Show hint
Replace the concatenated value with :searchTerm.
SOQL Injection Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
This lesson revisits Module 20's SOQL injection introduction with a security-module's depth — the full picture of how it happens and how to defend against it consistently.