Skip to content

Salesforce Prep

Expert Tips for Interviews & Certifications

  • Home
  • Current Page Parent Start Learning
  • About Me
  • Privacy Policy
  • Home
  • Current Page Parent Start Learning
  • About Me
  • Privacy Policy

LIST OF CONTENT

    • Order of Execution, Transactions, Savepoints, Partial Success & Locking in Salesforce
    • Record Types, Page Layouts, Dynamic Forms, and Picklist Strategy
    • Relationship Design: Master-Detail vs. Lookup, Junctions, and Roll-Ups
    • Mastering Salesforce Data Types: Objects, Fields, External Objects, Big Objects & Polymorphic Fields
    • Multi-Tenancy, Governor (Trust) Limits, Hyperforce & Data Residency in Salesforce
    • See all Platform & Data Model posts
    • Exception Handling & Error Management in Apex
    • Advanced OOP Concepts in Apex
    • Object-Oriented Programming in Apex
    • Collections & Data Structures in Apex
    • Control Flow & Logic in Apex
    • Apex Language Fundamentals
    • Salesforce Architecture, Org Types & Metadata
    • Apex Syntax Basics
    • Secure Coding in Salesforce: SOQL Injection, XSS/CSRF, and Secrets Hygiene
    • Callouts in Apex: Secure Auth, Non-Blocking UX, and Resilient Retries
    • Error Strategy in Salesforce Apex: Custom Exceptions, Fail-Fast Validation, Correlation IDs & Telemetry
    • Apex Security Essentials — with/without sharing and CRUD/FLS with Security.stripInaccessible
    • Service / Repository / Unit of Work in Apex — Keeping the Domain Layer Clean
    • See all Basic Apex & Programming posts
    • Packaging & Managed Packages in Salesforce
    • Apex Design Patterns
    • Logging, Debugging & Monitoring in Apex
    • Caching & Performance Enhancements in Apex
    • Custom Metadata & Configuration
    • Dynamic Apex & Metadata Access
    • Apex with Flow & Automation
    • Event-Driven Architecture in Salesforce
    • REST Services & Serialization in Apex
    • Integrations & Callouts in Apex
    • Asynchronous Apex
    • Testing Advanced Scenarios in Apex
    • Testing Apex Code
    • Security & Sharing in Apex
    • Governor Limits & Performance Tuning
    • Trigger Frameworks & Best Practices
    • Triggers Fundamentals
    • External Event Consumption in Salesforce — Retries & Dead-Letter Concepts
    • Pub/Sub API vs Streaming API (CometD/EMP): Ordering & At-Least-Once Delivery in Salesforce
    • Platform Events vs Change Data Capture — Use Cases & Trade-offs (Salesforce)
    • Event Schema Versioning, Correlation IDs, Idempotency & Deduplication in Salesforce
    • See all Advanced Apex posts
    • DML Operations & Transactions in Apex
    • Advanced SOQL & SOSL
    • SOQL Fundamentals
    • Salesforce Flow – Overview & Key Concepts
    • Platform Events with Idempotent Consumers and Durable Replay Options (Salesforce)
    • Handling Large Data Volumes in Salesforce: Smart Batch Design, QueryMore, and Governor Limit Strategies
    • Chaining Strategies, State Management, Error Handling & Monitoring in Salesforce Apex
    • Future vs Queueable vs Batch vs Schedulable in Salesforce Apex: A Practical Selection Guide
    • Transactional Integrity in Apex: Mastering Partial Success, Savepoints, and Rollbacks
    • Trigger Timing, Cross-Object Updates, and Asynchronous Escalation in Salesforce Apex
    • Bulkification, Mixed DML, and Lock Avoidance in Salesforce Apex
    • One Trigger per Object, Handler Pattern, and Recursion Guards in Salesforce Apex
    • Platform Cache Patterns in Salesforce — Safe Caching & Invalidation
    • SOSL vs SOQL, Search Tuning, and Skinny Tables
    • Relationship & Aggregate SOQL, Subqueries, and Avoiding N+1 in Salesforce
    • Salesforce SOQL/SOSL Selectivity & Query Plan — Standard, Custom & Compound Indexes
    • See all Automation Process posts
    • Middleware Patterns (MuleSoft / Kafka / AWS / Azure) & Error Routing — A Practical Integration Guide
    • Salesforce Integration Simplified: Webhooks, Platform Events & Callouts
    • OAuth 2.0: Choosing the Right Flow for Your App
    • API Contracts You Can Trust: Versioning, Pagination, Error Model, Idempotency Keys
    • Salesforce API Guide: REST, SOAP, Bulk, Composite, and GraphQL Explained
    • See all APIs & Integrations posts
    • Packaging & Managed Packages in Salesforce
    • Deployment & DevOps in Salesforce
    • Advanced Apex & Edge Cases
    • Dependency Injection & Clean Architecture in Apex
    • See all Security & Delivery posts
    • No posts yet
    • See all LWC posts
    • No posts yet
    • See all VISUAL FORCE posts
    • Interview, Certification & Project Readiness
    • Real-World Apex Best Practices
    • See all Pro & Career posts
    • No posts yet
    • See all Sub Category posts

Home » Secure Coding in Salesforce: SOQL Injection, XSS/CSRF, and Secrets Hygiene

Basic Apex & Programming

Secure Coding in Salesforce: SOQL Injection, XSS/CSRF, and Secrets Hygiene

Share

In Salesforce development — whether you’re working with Apex, LWC, Visualforce, or external integrations — even small mistakes can create serious security risks. Poor handling of user input or secrets can lead to data exposure, code execution, or unauthorized access.

To protect your Salesforce org, there are three essential security pillars every developer must understand:

  1. Prevent SOQL Injection – block malicious queries by handling input safely.

  2. Stop XSS and CSRF Attacks – safeguard your UI and API from script or request exploits.

  3. Follow Secrets Hygiene – store credentials properly and never hard-code them.

Below are the key concepts, best practices, and real-world code examples you can immediately apply in your org.


? SOQL Injection

Core Concept (What & Why)

SOQL injection happens when untrusted user input is directly concatenated into a query string.
Attackers can exploit this to modify query logic, bypass filters, or access restricted records.

To prevent this:

  • Use bind variables whenever possible.

  • If you need dynamic queries, escape user input properly.

  • Always whitelist fields and sorting parameters when building dynamic SOQL.


Real-World Example

Imagine a support form where users can search Accounts by name.
If an attacker submits a string like %’ OR Name LIKE ‘%’ --, your unprotected query might return every Account record in the org.

Bad (Vulnerable):

public with sharing class AccountSearch {
    public static List<Account> find(String q) {
        String soql = 'SELECT Id, Name FROM Account WHERE Name LIKE \'%' + q + '%\'';
        return Database.query(soql); // ❌ unsafe concat
    }
}

Good (Bind Variables + Safe Escape):

public with sharing class AccountSearchSafe {
    public static List<Account> find(String q) {
        // Prefer bind variables
        String pattern = '%' + q + '%';
        return [SELECT Id, Name FROM Account WHERE Name LIKE :pattern LIMIT 50];
    }

    public static List<Account> findDynamic(String q) {
        // If you must build dynamic SOQL, escape AND still bind where possible
        String safe = String.escapeSingleQuotes(q);
        String soql = 'SELECT Id, Name FROM Account WHERE Name LIKE \'%' + safe + '%\' LIMIT 50';
        return Database.query(soql);
    }
}

Bonus Tips:

  • Never concatenate user input directly into ORDER BY or field names.

  • Instead, use a whitelist approach:

  • String sort = (new Set<String>{'Name','CreatedDate'}).contains(userSort) ? userSort : 'Name';
    String soql = 'SELECT Id, Name FROM Account ORDER BY ' + sort + ' LIMIT 50';
    

⚔️ XSS (Cross-Site Scripting)

Core Concept (What & Why)

XSS occurs when untrusted HTML or JavaScript is rendered to a web page.
Salesforce frameworks like LWC and Visualforce automatically escape user input, but vulnerabilities arise when developers manually render unescaped HTML.

Always treat user input as plain text, not as executable HTML.


Real-World Example

Suppose a user leaves a comment containing a malicious <script> tag.
If that input is injected directly into the DOM using innerHTML, it can run scripts to steal session data or modify the page.

Bad (LWC – Dangerous DOM Injection):

// commentViewer.js
import { LightningElement, api } from 'lwc';
export default class CommentViewer extends LightningElement {
  @api commentHtml;
  renderedCallback() {
    this.template.querySelector('.slot').innerHTML = this.commentHtml; // ❌ XSS
  }
}

Good (LWC – Render as Text):

// commentViewer.js
import { LightningElement, api } from 'lwc';
export default class CommentViewer extends LightningElement {
  @api commentText = '';
}
<!-- commentViewer.html -->
<template>
  <div class="slds-text-body_regular">{commentText}</div> <!-- ✅ auto-escaped -->
</template>
<!-- Good: escape is true by default -->
<apex:outputText value="{!$CurrentPage.parameters.msg}" />
<!-- Bad: -->
<apex:outputText value="{!$CurrentPage.parameters.msg}" escape="false" /> <!-- ❌ -->

? CSRF (Cross-Site Request Forgery)

Core Concept (What & Why)

CSRF attacks trick a user’s browser into performing an action they didn’t intend, such as submitting a form or calling an API endpoint.

Salesforce automatically includes CSRF tokens for standard Visualforce, Aura, and LWC actions.
However, for custom REST endpoints or integrations, you must enforce CSRF protection manually.


Real-World Example

An attacker could host a malicious web page that silently sends a POST request to your org’s “mark invoice paid” API.
If your endpoint doesn’t validate a CSRF header token, the browser could execute that request under the victim’s session.

Apex REST with CSRF Header Check (Secure Pattern):

@RestResource(urlMapping='/pay/*')
global with sharing class PaymentRest {
    private static String requireCsrf() {
        String token = RestContext.request.headers.get('X-CSRF-Token');
        if (String.isBlank(token) || !CsrfTokens.verify(token)) {
            RestContext.response.statusCode = 403;
            throw new AuraHandledException('Invalid CSRF token');
        }
        return token;
    }

    @HttpPost
    global static void markPaid() {
        requireCsrf();
        // ... process safely ...
    }
}

public with sharing class CsrfTokens {
    // Issue/verify tokens tied to user + expiry.
    // Store the secret in Protected Custom Metadata (see next section).
    public static Boolean verify(String token) {
        // Minimal demo: verify HMAC + age
        try {
            Map<String,String> parts = (Map<String,String>)JSON.deserializeUntyped(EncodingUtil.base64Decode(token).toString());
            Datetime ts = Datetime.valueOf(parts.get('ts'));
            if (Datetime.now().getTime() - ts.getTime() > 15*60*1000) return false; // 15 min window
            String expected = hmac(parts.get('nonce') + ':' + parts.get('ts'));
            return expected == parts.get('mac');
        } catch (Exception e) {
            return false;
        }
    }
    private static String hmac(String msg) {
        String secret = SecretProvider.csrfSecret(); // ? from protected storage
        Blob mac = Crypto.generateMac('HmacSHA256', Blob.valueOf(msg), Blob.valueOf(secret));
        return EncodingUtil.convertToHex(mac);
    }
}

In real applications, issue tokens to clients safely via a GET request or embed them in the page state.
Then, send them back on every modifying request inside an X-CSRF-Token header.
Do not rely on cookies alone.


? Secrets Hygiene

Core Concept (What & Why)

Sensitive credentials like API keys, client secrets, and signing keys should never appear in your code, logs, or version control.
Hard-coded secrets can be easily leaked, so they must be stored securely in Salesforce-managed facilities.

Use:

  • Named Credentials for external API callouts (handles authentication securely).

  • Protected Custom Metadata or Settings for internal app secrets.

  • Avoid logging or exposing secrets in any way.

Rotate keys periodically and assign only the minimal permissions required.


Real-World Example

Let’s say you integrate with a payment gateway.
Instead of embedding the API key in your Apex class, you can use a Named Credential (best practice) or fetch the key from Protected Custom Metadata.

Using Named Credential (Preferred):

HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Payments_NC/v1/charges'); // ? secrets managed in Setup
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setBody(JSON.serialize(payload));
HTTPResponse res = new HTTP().send(req);

Using Protected Custom Metadata for App Secrets:

public with sharing class SecretProvider {
    public static String csrfSecret() {
        // Protected Custom Metadata record: Security_Config__mdt
        return Security_Config__mdt.getInstance('Default').CsrfSecret__c;
    }
}

public with sharing class ApiClient {
    public static void callWithKey() {
        String key = Security_Config__mdt.getInstance('Default').Payments_ApiKey__c; // protected
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://api.example.com/v1/charges');
        req.setMethod('POST');
        req.setHeader('Authorization', 'Bearer ' + key); // do not log!
        // ...
    }
}

Hygiene Checklist:
✅ Use Named Credentials for callouts (OAuth/JWT).
✅ Use Protected Custom Metadata/Settings for app secrets.
✅ Never log or email sensitive data.
✅ Rotate keys and restrict scope.
✅ Use pre-commit hooks or secret scanners to block accidental exposure.

Secure Coding


? Short Summary

To keep Salesforce apps secure and compliant:

  • Always bind or escape input to prevent SOQL injection.

  • Never render untrusted HTML or disable escaping — that’s how XSS happens.

  • Use custom header tokens for REST endpoints to block CSRF attacks.

  • Store secrets outside code, using Named Credentials or Protected Metadata.

These simple patterns dramatically harden your Salesforce org — without slowing down your development workflow.

 

  • October 20, 2025

Tags: ApexApex Best PracticesApex Secure CodingApex Security GuidelinesNamed Credentials SalesforceProtected Custom MetadataSalesforceSalesforce Application SecuritySalesforce CSRF ProtectionSalesforce Data ProtectionSalesforce Developer TipsSalesforce DevelopmentSalesforce Integration SecuritySalesforce Secrets ManagementSalesforce Secure Coding StandardsSalesforce SecuritySalesforce XSS ProtectionsecuritySOQL Injection Preventionsoql-injectionxss-csrf

Share on Facebook
Share on X
  • Next Apex Syntax Basics
  • Previous Callouts in Apex: Secure Auth, Non-Blocking UX, and Resilient Retries

You may also like...

  • Custom Metadata & Configuration

    Custom Metadata & Configuration

  • Caching & Performance Enhancements in Apex

    Caching & Performance Enhancements in Apex

  • Dependency Injection & Clean Architecture in Apex

    Dependency Injection & Clean Architecture in Apex

  • Testing Apex Code

    Testing Apex Code

  • salesforce soql selectivity query plan indexes hero

    Salesforce SOQL/SOSL Selectivity & Query Plan — Standard, Custom & Compound Indexes

  • Asynchronous Apex

    Asynchronous Apex

  • A flat style digital illustration visually represe.png

    External Event Consumption in Salesforce — Retries & Dead-Letter Concepts

  • salesforce soql subqueries aggregates n plus 1

    Relationship & Aggregate SOQL, Subqueries, and Avoiding N+1 in Salesforce

  • oauth2 flows guide.jpg

    Platform Events with Idempotent Consumers and Durable Replay Options (Salesforce)

  • salesforce platform events vs change data capture featured image.jpg

    Platform Events vs Change Data Capture — Use Cases & Trade-offs (Salesforce)

  • salesforce integration patterns aws azure dlq feature image.png

    Middleware Patterns (MuleSoft / Kafka / AWS / Azure) & Error Routing — A Practical Integration Guide

  • Security & Sharing in Apex

    Security & Sharing in Apex

  • Logging, Debugging & Monitoring in Apex

    Logging, Debugging & Monitoring in Apex

  • salesforce apex bulkification mixed dml lock avoidance feature image.jpg

    Bulkification, Mixed DML, and Lock Avoidance in Salesforce Apex

  • Trigger Frameworks & Best Practices

    Trigger Frameworks & Best Practices

Categories

Recent Posts

  • Interview, Certification & Project Readiness January 6, 2026
  • Real-World Apex Best Practices January 6, 2026
  • Packaging & Managed Packages in Salesforce January 6, 2026
  • Deployment & DevOps in Salesforce January 6, 2026
  • Advanced Apex & Edge Cases January 6, 2026
  • Dependency Injection & Clean Architecture in Apex January 6, 2026
  • Apex Design Patterns January 6, 2026
  • Logging, Debugging & Monitoring in Apex January 6, 2026
  • Caching & Performance Enhancements in Apex January 6, 2026
  • Custom Metadata & Configuration January 6, 2026

Tags

Selective Queries Selective SOQL Semi-Join Separation of Concerns Serverless Patterns Session cache sharing-and-security Shield Encryption Skinny Tables SNS Fanout Soft TTL SOQL soql-injection SOQL best practices SOQL Injection Prevention SOQL vs SOSL SOSL SQS DLQ Standard Objects Step Functions Streaming API Streaming API CometD stripinaccessible Testability Token Refresh Transactional Integrity Transaction Management Trigger Handler Pattern Triggers Trigger Timing Trust Limits Type-ahead search TYPEOF UI API Unit of Work UX Versioned keys versioning web security WhatId WhoId Without Sharing with sharing WITH SNIPPETS xss-csrf

RECENT POSTS

  • Interview, Certification & Project Readiness
  • Real-World Apex Best Practices
  • Packaging & Managed Packages in Salesforce
  • Deployment & DevOps in Salesforce
  • Advanced Apex & Edge Cases

SEARCH

Salesforce Prep © 2026. All Rights Reserved.