Study guide

10.1 Sharing, FLS, CRUD & Injection Prevention

Salesforce Certified Platform Developer I Exam

Track your progress as you read

Finished sections get a check mark.

1 Introduction & Exam Overview

1.1 Current Exam Facts 1.2 Blueprint Weights & Study Strategy

2 Platform Fundamentals

2.1 Multi-Tenant Architecture & Shared Resources 2.2 MVC Mapping on the Lightning Platform 2.3 Declarative vs Programmatic Decisions 2.4 Agentforce for Developers: Use Cases & Limitations

3 Data Modeling & Schema

3.1 Objects, Fields & Schema Design 3.2 Relationship Types & Implications 3.3 Schema Design Impact on Apex 3.4 Data Import & Export for Development

4 Platform Data Features

4.1 Formula Fields & Roll-Up Summaries 4.2 Core CRM Objects & Standard Schema 4.3 AppExchange Extensions & Platform Boundaries

5 Declarative Process Automation

5.1 Record-Triggered Flows & Declarative Automation 5.2 Approval Processes & Business Rules 5.3 When to Use Apex vs Declarative Tools

6 Apex Language Basics

6.1 Variables, Constants & Apex Data Types 6.2 Lists, Sets & Maps 6.3 Control Flow & Exception Handling 6.4 Classes, Interfaces & OOP Patterns

7 SOQL, SOSL & DML

7.1 SOQL Query Fundamentals 7.2 SOSL Search Fundamentals 7.3 DML Operations & Bulkification 7.4 Governor Limits & Transaction Boundaries

8 Apex Triggers & Order of Execution

8.1 Trigger Structure & Context Variables 8.2 Bulk Trigger Patterns & Best Practices 8.3 Save Order of Execution 8.4 Recursion, Cascading & Transaction Control

9 Asynchronous Apex

9.1 @future Methods 9.2 Queueable Apex 9.3 Batch Apex 9.4 Schedulable Apex & Job Orchestration

10 Security, Events & Schema Access

10.1 Sharing, FLS, CRUD & Injection Prevention 10.2 Platform Events Publish & Subscribe 10.3 Programmatic Schema Access (Describe)

11 Visualforce

11.1 Visualforce Pages & Markup 11.2 Standard, Custom Controllers & Extensions 11.3 Visualforce in Lightning Experience

12 Lightning Components

12.1 Lightning Component Framework Benefits 12.2 Aura Component Structure & Resources 12.3 Lightning Web Components Fundamentals 12.4 LWC Data Access: Wire, Imperative & Events

13 UI Composition & Apex Integration Patterns

13.1 Composing UI in Lightning Apps 13.2 UI Security, Performance & Accessibility Patterns 13.3 Apex Actions for Flow, LWC, and Agentforce

14 Apex Testing

14.1 Testing Framework & Coverage Requirements 14.2 Writing Unit Tests for Triggers & Classes 14.3 Test Data Strategies & Isolation 14.4 Executing Tests & Execute Anonymous Differences

15 Debugging & Developer Tools

15.1 Debug Logs & Monitoring 15.2 Developer Console, CLI, VS Code & Workbench 15.3 Sandboxes, Scratch Orgs & Environment Strategy

16 Deployment & Release

16.1 Change Sets & Metadata Deployment 16.2 Unlocked Packages, Metadata API & Salesforce DX 16.3 Release Readiness & Credential Maintenance

10.1 Sharing, FLS, CRUD & Injection Prevention

Key Takeaways Explain This Topic AI

with sharing enforces the running user's record-level sharing; without sharing ignores it; inherited sharing adopts the caller's class mode (default-safe for shared libraries)

CRUD/FLS are not automatic in Apex—use USER_MODE, WITH SECURITY_ENFORCED, Security.stripInaccessible, or explicit Schema describe isAccessible/isCreateable/isUpdateable/isDeletable checks

stripInaccessible removes fields the user cannot access from query results or DML-bound sObjects before you process or write them

Prevent SOQL injection with bind variables (:variable), never string-concatenate untrusted input into dynamic queries

Prevent XSS in Visualforce with HTMLENCODE, JSENCODE, JSINHTMLENCODE, and default merge-field escaping; understand CSRF protection for state-changing requests

Last updated: August 2026

10.1 Sharing, FLS, CRUD & Injection Prevention

Quick Answer: Apex runs in system mode by default for object/field permissions unless you opt into user-mode enforcement. Control record sharing with with sharing , without sharing , or inherited sharing . Enforce CRUD/FLS via USER_MODE , WITH SECURITY_ENFORCED , Security.stripInaccessible , or Schema describe checks. Stop SOQL injection with bind variables and XSS with Visualforce encode functions.

Platform Developer I treats security as a code-reading skill: you must recognize which keyword or API actually enforces what, and which “secure-looking” patterns still leave holes. Sharing, CRUD, and FLS are different layers—mixing them up is a common exam trap.

Three Layers of Data Security (Know the Difference)

  • Layer What it controls How Apex interacts
  • Object (CRUD) Create, Read, Update, Delete on an object type Not automatic in classic system-mode Apex
  • Field (FLS) Read/edit on individual fields Not automatic in classic system-mode Apex
  • Record (sharing) Which rows the user may see/edit Controlled by class sharing keywords

A class declared with sharing still bypasses CRUD/FLS unless you add USER_MODE, SECURITY_ENFORCED, stripInaccessible, or manual describe checks. Conversely, USER_MODE does not replace the need to understand sharing keywords for legacy system-mode paths.

  • Sharing Keywords on Apex Classes
  • with sharing public with sharing class AccountService {
  • public static List<Account> getAccounts() {
  • return [SELECT Id, Name FROM Account LIMIT 200];
  • }
  • }

SOQL and DML respect the running user's sharing rules (OWD, role hierarchy, sharing rules, manual shares, teams, etc.). Use for user-facing controllers and services that must never leak private records.

  • without sharing public without sharing class ComplianceRollupService {
  • public static void recomputeAll() {
  • // Intentionally sees records the interactive user might not own
  • List<Account> all = [SELECT Id, AnnualRevenue FROM Account];
  • // ... aggregate and write summary custom object the user can see
  • }
  • }

Ignores end-user record sharing so elevated operations can see the full dataset. Does not grant object/field permissions —it is not a CRUD/FLS free pass for permissions you never checked. Use sparingly and document why system-wide access is required (batch rollups, integration users acting for the org, etc.).

  • inherited sharing public inherited sharing class SharedUtility {
  • public static List<Contact> queryContacts(Id accountId) {
  • return [
  • SELECT Id, Name, Email
  • FROM Contact
  • WHERE AccountId = :accountId
  • ];
  • }
  • }

The class inherits the sharing mode of the caller:

  • Called from a with sharing class → behaves as with sharing
  • Called from a without sharing class → behaves as without sharing

Entry points with no explicit mode (some default system contexts) → treated carefully; Salesforce documents that inherited sharing defaults to enforcing sharing when the class is used as an entry point in many scenarios—know the intent: libraries should not silently escalate

Exam heuristic: Prefer inherited sharing for reusable utilities so a secure caller stays secure. Prefer explicit with sharing for Visualforce/Lightning controllers. Prefer without sharing only when the requirement is org-wide data access that the user must not have interactively.

Inner classes inherit the outer class’s sharing declaration unless they declare their own.

  • Enforcing CRUD and FLS
  • 1. USER_MODE (modern default for new code) // SOQL in user mode
  • List<Account> accounts = [
  • SELECT Id, Name, AnnualRevenue
  • FROM Account
  • WITH USER_MODE
  • LIMIT 100
  • ];
  • // DML in user mode
  • Database.insert(newAccount, AccessLevel.USER_MODE);
  • Database.update(accounts, AccessLevel.USER_MODE);

USER_MODE applies the running user’s object and field permissions (and related security rules for that mode). Operations fail or strip access according to the API when the user lacks rights—ideal for interactive UI paths.

System mode (historical default) is still available as AccessLevel.SYSTEM_MODE / WITH SYSTEM_MODE when a trusted automation must run elevated—pair it with deliberate design, not as a lazy default.

  • 2. WITH SECURITY_ENFORCED (SOQL only) List<Contact> contacts = [
  • SELECT Id, Name, Email, SSN__c
  • FROM Contact
  • WITH SECURITY_ENFORCED
  • LIMIT 50
  • ];

If the user lacks FLS or object read on any field/object in the query, the platform throws a System.QueryException rather than returning partial data. Excellent for “fail closed” reads. It does not replace DML security by itself—pair with stripInaccessible, USER_MODE DML, or describe checks for writes.

  • 3. Security.stripInaccessible List<Account> queried = [
  • SELECT Id, Name, AnnualRevenue, Restricted_Notes__c
  • FROM Account
  • LIMIT 200
  • ];
  • SObjectAccessDecision decision = Security.stripInaccessible(
  • AccessType.READABLE,
  • queried
  • );
  • List<Account> safe = decision.getRecords();
  • // Fields the user cannot read are removed from the in-memory sObjects

Common AccessType values:

  • AccessType Use when
  • READABLE Cleaning query results before sending to UI or external consumers
  • CREATABLE Before insert—drop fields user cannot create
  • UPDATABLE Before update—drop fields user cannot edit
  • UPSERTABLE Before upsert paths

stripInaccessible does not remove whole records the user cannot see under sharing; it sanitizes fields on the sObjects you already retrieved. Still use sharing keywords or user-mode queries appropriately for row visibility. // DML pattern: strip then write

  • SObjectAccessDecision writeDecision = Security.stripInaccessible(
  • AccessType.CREATABLE,
  • new List<Account>{ draftAccount }
  • );
  • insert writeDecision.getRecords();
  • 4. Explicit Schema describe checks if (!Schema.sObjectType.Account.isCreateable()) {
  • throw new AuraHandledException('No permission to create Accounts');
  • }
  • if (!Schema.sObjectType.Account.fields.AnnualRevenue.isUpdateable()) {
  • throw new AuraHandledException('No permission to edit Annual Revenue');
  • }

Manual checks remain valid and appear often on older exam items. They scale poorly if copy-pasted field-by-field without helpers—but recognition of isAccessible , isCreateable , isUpdateable , isDeletable (object and field) is required.

  • SOQL Injection Prevention
  • Dynamic SOQL built from user input is a classic vulnerability: // INSECURE — never do this
  • String name = userInput; // e.g. "x' OR Name != '"
  • String q = 'SELECT Id FROM Account WHERE Name = \'' + name + '\'';
  • List<Account> rows = Database.query(q);

A crafted string can change the WHERE clause logic and expose data.

  • Safe pattern — bind variables: String name = userInput;
  • List<Account> rows = [
  • SELECT Id, Name FROM Account WHERE Name = :name
  • ];
  • // or dynamic SOQL with binds
  • List<Account> rows2 = Database.query(
  • 'SELECT Id, Name FROM Account WHERE Name = :name'
  • );

Bind variables are treated as values , not query text—injection of extra clauses fails. When you must accept field/object names dynamically, whitelist against Schema describe maps rather than concatenating free-form identifiers. Map<String, Schema.SObjectField> fieldMap =

  • Schema.SObjectType.Account.fields.getMap();
  • if (!fieldMap.containsKey(requestedField)) {
  • throw new IllegalArgumentException('Invalid field');
  • }
  • // only then use the validated API name in dynamic SOQL

String.escapeSingleQuotes reduces quote-based breakage but is not a complete substitute for binds and whitelisting on the exam’s preferred answers.

XSS Prevention in Visualforce

Cross-site scripting injects attacker script into pages viewed by other users. In Visualforce:

  • Defense Role
  • Default merge-field escaping Many {!...} outputs are HTML-escaped by default
  • HTMLENCODE Encode for HTML body context
  • JSENCODE Encode for JavaScript string context
  • JSINHTMLENCODE Encode when JS appears inside HTML attributes/context
  • URLENCODE Encode for URL query components

Avoid escape="false" Disabling escape on apex:outputText is a red flag unless content is trusted and required <!-- Prefer encoding when rendering untrusted data into scripts -->

  • <script>
  • var name = '{!JSENCODE(Account.Name)}';
  • </script>
  • <apex:outputText value="{!HTMLENCODE(userComment)}" escape="false" />
  • <!-- Better: leave escape true and avoid raw HTML unless necessary -->

If a snippet shows user input rendered with escape="false" and no encode function, mark it insecure .

CSRF Basics

Cross-Site Request Forgery tricks a logged-in browser into submitting a state-changing request the user did not intend. Salesforce Visualforce and many platform endpoints include CSRF tokens on forms and require proper request methods for mutations. Exam awareness:

  • Prefer framework form posts over ad-hoc GETs that mutate data
  • Do not disable CSRF protections
  • Custom HTTP endpoints and sites need explicit anti-CSRF design

You rarely write the token by hand; you must recognize that ignoring CSRF or using GET for deletes/updates is unsafe.

Exam Recognition of Insecure Snippets

When the question shows code, scan in this order:

Sharing — Does a user-facing class omit with sharing / use without sharing without justification?

CRUD/FLS — System-mode query of sensitive fields with no USER_MODE, SECURITY_ENFORCED, stripInaccessible, or describe checks?

Injection — String concatenation into Database.query or dynamic SOSL?

XSS — Unescaped output, escape="false" , user data inside <script> without JSENCODE?

False confidence — with sharing alone does not equal full CRUD/FLS compliance. // Classic trap: looks careful, still system-mode FLS

  • public with sharing class ProfileController {
  • @AuraEnabled
  • public static Account getAccount(Id accountId) {
  • return [
  • SELECT Id, Name, Restricted_Field__c
  • FROM Account
  • WHERE Id = :accountId
  • ]; // sharing OK; FLS not enforced
  • }
  • }

Hardening options: add WITH USER_MODE / WITH SECURITY_ENFORCED , or strip inaccessible fields before return.

Putting It Together

Secure Apex is layered: sharing keywords for rows, USER_MODE / SECURITY_ENFORCED / stripInaccessible / describe for objects and fields, binds and whitelists against injection, and encode/escape against XSS—plus platform CSRF defaults for forms. On the exam, match the vulnerability in the stem to the correct control; do not pick “with sharing” as a universal answer for FLS questions.