Salesforce has remained a popular choice for CRM platforms. From customizing workflows to building applications, businesses can seamlessly achieve their goals with this cloud-based platform. What’s more, the extended functionality, like Visualforce pages, Lightning Web Components (LWC), Aura Components, and Apex, aids development for the enterprises significantly.
We saw few vulnerabilities and security controls provided by Salesforce platform in past couple of blogs. We are going to discuss about two more common and severe vulnerabilities - Cross-Site Scripting (XSS) and SOQL Injection in this blog.
Cross-Site Scripting (XSS) in Salesforce
XSS occurs when an application takes untrusted user input and returns the response containing user input without encoding to the browser. Attackers take this opportunity to run malicious JavaScript in the victim’s browser and extract sensitive information.In Salesforce, XSS can appear in:
- Visualforce Pages: Using raw {!} expressions without escaping.
- Aura Components / LWC: Unsafe DOM manipulation or improper attribute use.
- JS Controllers: Unvalidated data is passed straight into the user interface.
How to Detect XSS in Code
- Unescaped Output in Visualforce → Flag <apex:outputText value="{!userInput}" escape="false"/> or direct use of {!userInput} without proper encoding
- Improper aura:unescapedHtml in Aura → Any use of aura:unescapedHtml or dynamic attributes directly rendering user data
- Direct innerHTML assignment in LWC/JS → Using element.innerHTML = userInput instead of textContent. Moreover, the usage of insecure JavaScript functions such as html(), eval()
- Input Fields Without Validation → Inputs accepted from users (comments, descriptions, messages) should be validated or sanitized before use
Visualforce Page (Vulnerable):
<apex:page controller="XSSExampleController">
<apex:form>
<apex:inputText value="{!userInput}" label="Enter your name:"/>
<apex:commandButton value="Submit" action="{!processInput}"/>
<br/>
<!-- Directly rendering user input -->
<apex:outputText value="{!userInput}" escape="false"/>
</apex:form>
</apex:page>
<apex:form>
<apex:inputText value="{!userInput}" label="Enter your name:"/>
<apex:commandButton value="Submit" action="{!processInput}"/>
<br/>
<!-- Directly rendering user input -->
<apex:outputText value="{!userInput}" escape="false"/>
</apex:form>
</apex:page>
Controller:
public class XSSExampleController {
public String userInput {get; set;}
public void processInput() {
// No validation or sanitization here
}
}
public String userInput {get; set;}
public void processInput() {
// No validation or sanitization here
}
}
If the attacker enters, <script>alert('XSS Attack!');</script> attack vector it will execute in the victim’s browser.
Safe Example
Visualforce Page (Safe):
<apex:outputText value="{!userInput}" escape="true"/>
By default, escape value is true.
Or manually encode:
<apex:outputText value="{!HTMLENCODE(userInput)}"/>
In LWC, avoid assigning user input directly to innerHTML/html():
// Vulnerable
element.innerHTML = userInput;
// Safe
element.textContent = userInput;
element.innerHTML = userInput;
// Safe
element.textContent = userInput;
Impact
By exploiting XSS vulnerability, an attacker can steal user session. Once an attacker gets access to user session, he can perform tasks on behalf of the user which can result in data loss. In other cases, an attacker can redirect user to phishing site or can deface the application.
SOQL Injection in Salesforce
What is SOQL Injection?
SOQL Injection is similar to SQL Injection in traditional applications. This occurs when the untrusted user input is directly combined into a dynamic SOQL query string. Once coupled, the attackers may be able to access unauthorized data or bypass restrictions by manipulating the query.
SOQL Injection is similar to SQL Injection in traditional applications. This occurs when the untrusted user input is directly combined into a dynamic SOQL query string. Once coupled, the attackers may be able to access unauthorized data or bypass restrictions by manipulating the query.
How to detect in Code
When reviewing Salesforce Apex code, focus on how queries are built:
- Dynamic SOQL with Concatenation → Flag any use of Database.query() or string concatenation (+) with user-supplied input
String q = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';
Database.query(q);
Database.query(q);
- Red flag when user input (e.g., from ApexPages.currentPage().getParameters(), form fields, or API requests) is directly concatenated
String searchKey = ApexPages.currentPage().getParameters().get('search');
String query = 'SELECT Id FROM Contact WHERE Email LIKE \'%' + searchKey + '%\'';
List<Contact> contacts = Database.query(query);
String query = 'SELECT Id FROM Contact WHERE Email LIKE \'%' + searchKey + '%\'';
List<Contact> contacts = Database.query(query);
Apex Controller (Vulnerable):
public with sharing class SOQLInjectionExample {
@AuraEnabled(cacheable=true)
public static List<Account>searchAccounts(String inputName) {
// VULNERABLE: direct string concatenation
String query = 'SELECT Id, Name FROM Account WHERE Name LIKE \'%' + inputName + '%\'';
return Database.query(query);
}
}
@AuraEnabled(cacheable=true)
public static List<Account>searchAccounts(String inputName) {
// VULNERABLE: direct string concatenation
String query = 'SELECT Id, Name FROM Account WHERE Name LIKE \'%' + inputName + '%\'';
return Database.query(query);
}
}
Here, an attacker could supply input like,
test%' OR Account LIKE '
This would alter the query to return all accounts, bypassing intended restrictions.Secure Code in Apex:
- Safe queries use bind variables (:variable) instead of concatenation.
String searchKey = ApexPages.currentPage().getParameters().get('search');
List<Contact> contacts = [SELECT Id, Name FROM Account WHERE LIKE :('%' + inputName + '%')];
List<Contact> contacts = [SELECT Id, Name FROM Account WHERE LIKE :('%' + inputName + '%')];
- Verify Input Validation and Escaping - even with dynamic queries, Salesforce provides String.escapeSingleQuotes() to neutralize malicious input.
String userInput = ApexPages.currentPage().getParameters().get('name');
userInput = String.escapeSingleQuotes(userInput);
String query = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';
List<Account> accList = Database.query(query);
userInput = String.escapeSingleQuotes(userInput);
String query = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';
List<Account> accList = Database.query(query);
Impact
Like any SQL Injection, a successful exploitation of SOQL Injection can result in data loss which will result in compliance violation and can cause damage to customer trust and reputation of the company.