Org Skills

salesforce-security

Designs and hardens security on the Salesforce Platform — enforcing sharing and field-level security in Apex with USER_MODE, stripInaccessible and `with sharing`, guest user and Experience Cloud site hardening, org posture through Health Check, MFA and session settings, Shield Platform Encryption and Event Monitoring, Trusted URLs and CSP for Lightning Web Security, named credentials over stored secrets, and the Code Analyzer v5 security engines in CI.

Download .zip Raw Source
When agents use itUse this whenever the user writes SOQL or DML that must respect the running user's access, sees WITH SECURITY_ENFORCED in inherited code, exposes data to unauthenticated guest users, hardens an Experience Cloud site, configures MFA, session or IP restrictions, evaluates Shield or Event Monitoring, adds a third-party script or endpoint that needs a Trusted URL, or prepares an app for AppExchange listing. For Apex idioms use `apex-development`.

Install

Copilot (VS Code, Visual Studio, Copilot CLI and github.com) reads skills from the repository — commit them so the whole team gets them.

npx skills add AGCO-Global/org-skills --skill salesforce-security -a github-copilot
# or with the org installer (adds .github/skills/salesforce-security):
npx -y github:AGCO-Global/org-skills add skill salesforce-security

Uses the open skills CLI. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, OpenCode, Windsurf and 60+ others — it asks which agent to install into.

npx skills add AGCO-Global/org-skills --skill salesforce-security
# user-level instead of project-level:
npx skills add AGCO-Global/org-skills --skill salesforce-security -g

Installs the salesforce-security-skills plugin, which bundles all Salesforce / Security skills and keeps them updated.

/plugin marketplace add AGCO-Global/org-skills
/plugin install salesforce-security-skills@org-skills
# or just this skill, in this repository:
npx skills add AGCO-Global/org-skills --skill salesforce-security -a claude-code

Use Download .zip above, then upload it under Customize → Skills → Upload skill. Team and Enterprise admins can sync this repo as a plugin marketplace instead.

Installs into .agents/skills/, which Codex reads.

npx skills add AGCO-Global/org-skills --skill salesforce-security -a codex

Installs into Cursor's skills folder.

npx skills add AGCO-Global/org-skills --skill salesforce-security -a cursor

Installs into Gemini CLI's skills folder.

npx skills add AGCO-Global/org-skills --skill salesforce-security -a gemini-cli

Any tool with rules, instructions or custom prompts: use Copy SKILL.md above and paste it in. It is plain Markdown.

Commands use your normal git sign-in to GitHub, so they work while the repository is private. Node.js 20+ required.

Try it — example prompts

Prompts this skill is tested against, and what a good answer includes.

  • Should this dynamic SOQL use WITH SECURITY_ENFORCED?

    no — WITH USER_MODE supersedes WITH SECURITY_ENFORCED Database.queryWithBinds(q, binds, AccessLevel.USER_MODE) for dynamic SOQL USER_MODE covers polymorphic fields and gives better errors replace, never combine the two clauses stripInaccessible only for the system-mode-result-returned-to-user case

  • Our class is declared `with sharing`. Is our data access secure?

    with sharing covers record access only object and field permissions still run in system mode add WITH USER_MODE on queries and AccessLevel.USER_MODE on DML three separate enforcement concerns

  • We're building a public Experience Cloud site where visitors can submit a request.

    guest user is the unauthenticated internet — grant nothing by default guest record access is capped at read; writes go through Apex you control every guest-reachable @AuraEnabled method is an unauthenticated endpoint validate all inputs and do not trust an id parameter enable secure guest user record access and test logged out

  • Where should we store the API key for our payment provider callout?

    Named Credential with an External Credential custom settings and custom metadata are visible to anyone who can view setup secrets in metadata travel in change sets and packages rotation should not require a code deploy

  • Set up static analysis for security in our CI pipeline.

    Code Analyzer v5: sf plugins install code-analyzer, sf code-analyzer run sf scanner run (v4) was retired in August 2025 enable the Salesforce Graph Engine for path-based CRUD/FLS analysis configure engines and severities in code-analyzer.yml agree which severities fail the build

  • Should we turn on Shield Platform Encryption for all our PII fields?

    decide per field, not per object encrypted fields lose sorting, some filtering and indexing behaviour check every report, list view, SOQL filter and automation touching the field test in a sandbox before production encrypt what regulation requires rather than everything sensitive-looking

Skill contents

Salesforce Security

Targets: Salesforce Spring '26 · Code Analyzer v5 · Lightning Web Security · Verified: 2026-09 against https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_keywords_sharing.htm and https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/

Salesforce gives you a strong permission model and then lets Apex run right past it. Apex executes in system mode by default: sharing rules, object permissions and field-level security are all ignored unless you say otherwise. So platform security is mostly a discipline of enforcing, in code, the access the admin already configured — and of noticing the places (guest users, integration users, Experience Cloud sites) where "the admin configured it" means something much more permissive than you assumed.

1. Decide first

Question Default Change when
Class sharing declaration with sharing, declared explicitly on every class without sharing only with a comment justifying it. The org standard uses these two keywords only
Static SOQL access WITH USER_MODE System mode only for a deliberate, documented elevation
Dynamic SOQL Database.queryWithBinds(q, binds, AccessLevel.USER_MODE) Never string-concatenate user input into the query
DML access Database.insert(records, AccessLevel.USER_MODE) System mode only where the operation is genuinely privileged
WITH SECURITY_ENFORCED in existing code Replace it with WITH USER_MODE Never combine the two
System-mode query returned to a user Security.stripInaccessible before returning Not needed when the query already ran in user mode
Guest user access Assume it is public internet; grant nothing by default Every guest-accessible object is a decision to defend
Secrets for callouts Named Credential (+ External Credential) The org also sanctions Credential__c (encrypted field, FLS restricted to the integration user, kept out of change sets); never a custom setting, custom metadata, static resource or hard-coded string
Static analysis Code Analyzer v5 in CI with the security engines enabled sf scanner run (v4) was retired in August 2025

2. Enforce access in Apex

Apex runs in system mode. Three separate things must be enforced, and with sharing only covers the first:

  • Record access (sharing)with sharing on the class.
  • Object and field permissions (CRUD/FLS)WITH USER_MODE on the query, AccessLevel.USER_MODE on the DML.
  • What you hand back — a system-mode query returning records to a user needs Security.stripInaccessible.
public with sharing class OrderService {
    public List<Order> recentOrders(Id accountId) {
        return [
            SELECT Id, Name, Amount, Status
            FROM Order
            WHERE AccountId = :accountId
            WITH USER_MODE
            ORDER BY CreatedDate DESC
            LIMIT 50
        ];
    }
}

WITH USER_MODE supersedes WITH SECURITY_ENFORCED: it covers polymorphic fields and gives better errors. When you find the old clause, replace it — never write both on one query.

The full enforcement matrix, including which construct covers what and where each one silently does not apply: references/sharing-and-crud-fls.md.

3. Guest users and Experience Cloud

The guest user is the unauthenticated internet, and it is where Salesforce data leaks happen.

  • Start from zero: no object permissions, no record access, guest sharing rules only where genuinely required.
  • Guest user record access is capped at read; anything a guest "creates" happens through Apex you control — so that Apex is a public API and must validate everything.
  • An @AuraEnabled method reachable by a guest is an unauthenticated endpoint. Check with sharing, check CRUD/FLS, validate every input, and do not trust an id parameter to be one the caller may see.
  • Review what the site's standard components expose, not just your custom ones.

4. Org posture

  • Health Check gives a baseline score against Salesforce's standard: session settings, password policy, certificate and sharing settings. Run it, fix what it flags, re-run after every release.
  • MFA is required; enforce it through the org's session settings rather than relying on users. Add IP ranges and session timeouts appropriate to the profile rather than one blanket policy.
  • Shield Platform Encryption protects data at rest from platform-level exposure, with real functional costs — encrypted fields lose some filtering, sorting and indexing. Decide field by field, and confirm each one does not break a report or a SOQL filter the business depends on.
  • Event Monitoring supplies the audit trail: logins, API calls, report exports, Apex executions. Without it, "did anyone export that object" has no answer.

Health Check items, Shield trade-offs, Event Monitoring event types and a guest-user hardening checklist: references/org-hardening.md.

5. Client-side and integrations

  • Lightning Web Security is the runtime for components (default for orgs created since Winter '23). It isolates component JavaScript; code that reached into the DOM or global objects under Locker needs revisiting when migrating.
  • Third-party scripts load from a static resource, not a CDN, and any external endpoint the page contacts needs a Trusted URL with the right CSP directives.
  • Outbound callouts authenticate through a Named Credential with an External Credential. Secrets in custom metadata or custom settings are readable by anyone who can view setup, and they end up in change sets.
  • Inbound integrations get their own integration user with a minimal permission set — not a system administrator licence, and not a departing employee's account.

6. Static analysis in CI

Code Analyzer v5 replaced the retired v4 (sf scanner run) in August 2025, and runs PMD, ESLint, RetireJS, the Flow scanner, CPD, regex rules and the Salesforce Graph Engine in one result set:

sf plugins install code-analyzer
sf code-analyzer run --workspace force-app --rule-selector Security --view detail

Enable the Graph Engine for CRUD/FLS analysis — it is the engine that finds access violations across call paths, which PMD alone cannot. Configure engines and severities in code-analyzer.yml and fail the build on the severities you have agreed to treat as blocking.

Deliverable format

## Exposure — what data, which audiences (internal, community, guest, integration)
## Apex enforcement — class sharing, query and DML access level, per entry point
## Guest and community — object permissions, sharing, and every guest-reachable Apex entry point
## Org posture — Health Check findings, MFA, session and IP policy
## Data protection — Shield decisions per field, Event Monitoring events retained
## Integrations — named credentials, integration users and their permission sets
## Client-side — Trusted URLs, CSP, static resources, LWS migration notes
## CI — Code Analyzer configuration and the failing severities
## Open questions

Checklist

  • Every class declares with sharing, or without sharing with a stated reason — none omits the keyword.
  • Every user-facing query uses WITH USER_MODE; DML uses AccessLevel.USER_MODE.
  • No WITH SECURITY_ENFORCED remains, and it is never combined with USER_MODE.
  • System-mode results returned to users pass through Security.stripInaccessible.
  • Dynamic SOQL uses bind variables — no string concatenation of user input.
  • Guest user profiles grant the minimum, and every guest-reachable @AuraEnabled method validates its inputs.
  • Health Check has been run this release and its findings triaged.
  • MFA, session timeout and IP policy are set per profile, not one blanket rule.
  • Shield field choices were checked against the reports and filters that use them.
  • Every callout secret is in a Named Credential, or in Credential__c with the field encrypted and FLS restricted; none in custom settings or metadata.
  • Integration users have minimal permission sets.
  • Third-party scripts are static resources, with Trusted URLs and CSP configured.
  • Code Analyzer v5 runs in CI with the Graph Engine enabled and a failing severity agreed.

Anti-patterns

Anti-pattern Why it hurts Fix
without sharing with no comment Silently returns records the user may not see with sharing, or without sharing with a stated reason
with sharing treated as full enforcement It covers record access only — fields and objects are still system mode Add WITH USER_MODE and AccessLevel.USER_MODE
Adding WITH SECURITY_ENFORCED to new code Superseded; weaker on polymorphic fields WITH USER_MODE
Both clauses on one query Confusing and redundant Keep USER_MODE only
String-concatenated dynamic SOQL SOQL injection Database.queryWithBinds with AccessLevel.USER_MODE
Guest user granted object permissions "to make it work" Publishes data to the internet Grant nothing; expose through controlled Apex with validation
API key in custom metadata Visible to anyone who can view setup; travels in change sets Named Credential with External Credential, or Credential__c encrypted and FLS-restricted
Integration running as a system administrator One compromised integration owns the org Dedicated integration user with a minimal permission set
sf scanner run in the pipeline Retired August 2025 sf code-analyzer run with code-analyzer.yml
Third-party script from a CDN Blocked by CSP, and unreviewed code in your page Static resource plus a Trusted URL

Go deeper

  • references/sharing-and-crud-fls.md — the enforcement matrix, what each construct does and does not cover, stripInaccessible patterns, and migrating WITH SECURITY_ENFORCED.
  • references/org-hardening.md — Health Check items, MFA and session policy, Shield trade-offs per field type, Event Monitoring events, guest-user hardening, and the checks an AppExchange listing must pass.
  • Sibling skills: apex-development for Apex idioms and bulkification; lwc-development for component patterns under LWS; salesforce-integration for authentication flows; salesforce-org-conventions for the org's naming and mandated patterns.

References

Deeper material the agent loads only when needed.