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.- 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.
- 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: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 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):
By default, escape value is true.
Or manually encode:
In LWC, avoid assigning user input directly to innerHTML/html():
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
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
Database.query(q);
- Red flag when user input (e.g., from ApexPages.currentPage().getParameters(), form fields, or API requests) is directly concatenated
String query = 'SELECT Id FROM Contact WHERE Email LIKE \'%' + searchKey + '%\'';
List<Contact> contacts = Database.query(query);
Apex Controller (Vulnerable):
@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,
Secure Code in Apex:
- Safe queries use bind variables (:variable) instead of concatenation.
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.
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.