agentleFS
jiten-singh-shahijiten-singh-shahi/salesforce-claude-code/.cursor/skills/sf-security-constraints/SKILL.md

sf-security-constraints

Skill15 starsChanged 7 months agoMITView on GitHub

Enforce CRUD/FLS, sharing model, SOQL injection prevention, and XSS protection for Apex and LWC. Use when writing or reviewing ANY Apex, trigger, LWC, or VF page. Do NOT use for Flow-only configuration.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Prefer WITH USER_MODE / AccessLevel.USER_MODE for all new code (see @../_reference/API_VERSIONS.md for minimum version).

    line 98
  2. Very specific:

    Use <apex:outputField> or <apex:outputText escape="true"> where possible -- they handle encoding automatically.

    line 112
  3. Distinctive:

    When reviewing or writing code, check constraints in this order:

    line 118

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Security Constraints for Salesforce Code

When to Use

This skill auto-activates when writing, reviewing, or modifying any Apex class, trigger, LWC component, or Visualforce page. It enforces CRUD/FLS checks, sharing model compliance, SOQL injection prevention, and XSS protection for all Salesforce code.

Hard rules that apply to every Apex class, trigger, LWC component, and Visualforce page. Violating any constraint below is a blocking issue that must be fixed before the code is considered complete.

Reference: @../_reference/SECURITY_PATTERNS.md, @../_reference/SHARING_MODEL.md @../_reference/DEPRECATIONS.md


Never Do

#ConstraintWhy
N1Skip CRUD/FLS checks on user-facing SOQL or DMLExposes data the running user should not see or modify
N2Use without sharing without a written justification commentSilently bypasses record-level security for every query in the class
N3Build SOQL with string concatenation of user inputSOQL injection -- attacker can read or modify arbitrary records
N4Trust client-side input without server-side validationClient payloads are trivially forgeable; all validation must repeat in Apex
N5Use element.innerHTML = userInput in LWCDirect XSS vector; LWC auto-encoding is bypassed
N6Hardcode API keys, tokens, passwords, or record IDs in ApexCredentials leak via source control; IDs differ across orgs
N7Log sensitive field values with System.debugDebug logs are accessible to admins and can be exported
N8Omit the sharing keyword on a class entirelyDefaults to without sharing in most contexts -- an implicit security bypass

Always Do

#ConstraintHow
A1Enforce CRUD + FLS on user-facing queriesWITH USER_MODE in SOQL (see @../_reference/API_VERSIONS.md for minimum version)
A2Enforce CRUD + FLS on user-facing DMLDatabase.insert(records, false, AccessLevel.USER_MODE)
A3Use with sharing as the default class keywordSwitch to inherited sharing only for utility/helper classes
A4Use bind variables for SOQL filter valuesStatic SOQL :bindVar or Database.queryWithBinds()
A5Sanitize output in VisualforceHTMLENCODE, JSENCODE, JSINHTMLENCODE, URLENCODE per context
A6Use textContent or <lightning-formatted-rich-text> in LWCNever assign user-controlled strings to innerHTML
A7Store credentials in Named Credentials / External CredentialsUse callout:NamedCredential prefix in Apex HTTP requests
A8Document every without sharing usageInclude: why sharing bypass is needed, who approved, date reviewed
A9Whitelist-validate dynamic SOQL componentsSort fields, directions, object/field names must match a known-safe set
A10Use Security.stripInaccessible() when silent field removal is acceptableAlways check getRemovedFields() to avoid downstream NullPointerException

Sharing Keyword Decision

Apply the correct keyword on every class. Reference: @../_reference/SHARING_MODEL.md

User-facing code (LWC, VF, Aura, REST API)?     -->  with sharing
Utility / helper called from mixed contexts?     -->  inherited sharing
Scheduled batch / system-only processing?        -->  without sharing  (document justification)
Trigger handler?                                 -->  with sharing  (call without sharing helper only if justified)
Inner class?                                     -->  declare explicitly  (does NOT inherit outer class keyword)
Omitted / unsure?                                -->  with sharing

Key rule: sharing context does not propagate to called classes. A with sharing class calling a without sharing class runs the called method without sharing.


Anti-Pattern Table

Anti-PatternSecurity ImpactCorrect Pattern
Database.query('... WHERE Name = \'' + input + '\'')SOQL injection -- attacker reads/modifies arbitrary data[SELECT ... WHERE Name = :input WITH USER_MODE] or Database.queryWithBinds()
public class FooController { ... } (no sharing keyword)Implicit without sharing -- returns all recordspublic with sharing class FooController { ... }
public without sharing class AccountCtrl (user-facing)All records visible regardless of OWD, role hierarchy, sharing rulespublic with sharing class AccountCtrl
insert records; in user-facing codeNo CRUD/FLS enforcementDatabase.insert(records, false, AccessLevel.USER_MODE);
element.innerHTML = serverData in LWCStored/reflected XSSelement.textContent = serverData
req.setHeader('Authorization', 'Bearer ' + hardcodedToken)Credential in source code; leaks via SCMcallout:Named_Credential with External Credentials
{!rawMergeField} in VisualforceReflected XSS{!HTMLENCODE(rawMergeField)} or <apex:outputText escape="true">
System.debug('SSN: ' + contact.SSN__c)PII in debug logsRemove sensitive field logging; use opaque identifiers
API_Keys__c.getOrgDefaults().Token__c for authSecrets in queryable Custom SettingExternal Credentials (see @../_reference/API_VERSIONS.md for minimum version)
SOQL without LIMIT in user-facing contextUnbounded query; governor limit risk + data exposureAdd LIMIT clause; paginate with OFFSET or cursor

CRUD/FLS Enforcement Quick Reference

Reference: @../_reference/SECURITY_PATTERNS.md

ApproachMin APIEnforcesOn Violation
WITH USER_MODE (SOQL)See @../_reference/API_VERSIONS.mdCRUD + FLSThrows QueryException
AccessLevel.USER_MODE (DML)See @../_reference/API_VERSIONS.mdCRUD + FLSThrows DmlException
WITH SECURITY_ENFORCED (SOQL)See @../_reference/API_VERSIONS.mdCRUD + FLS (reads)Throws QueryException
Security.stripInaccessible()See @../_reference/API_VERSIONS.mdFLS onlySilently strips fields
Manual isAccessible() / isCreateable()AllCRUD onlyDeveloper-controlled

Prefer WITH USER_MODE / AccessLevel.USER_MODE for all new code (see @../_reference/API_VERSIONS.md for minimum version). Fall back to stripInaccessible only when silent field removal is the desired behavior.


Visualforce Encoding Quick Reference

Output ContextEncoding FunctionExample
HTML bodyHTMLENCODE{!HTMLENCODE(account.Description)}
HTML attributeHTMLENCODEtitle="{!HTMLENCODE(account.Name)}"
JavaScript stringJSENCODEvar x = '{!JSENCODE(account.Name)}'
JS in HTML attributeJSINHTMLENCODEonclick="fn('{!JSINHTMLENCODE(val)}')"
URL parameterURLENCODEhref="/page?q={!URLENCODE(val)}"

Use <apex:outputField> or <apex:outputText escape="true"> where possible -- they handle encoding automatically.


Enforcement Priority

When reviewing or writing code, check constraints in this order:

  1. Sharing keyword declared on every class (N2, N8, A3)
  2. CRUD/FLS enforced on all user-facing SOQL and DML (N1, A1, A2)
  3. SOQL injection -- no string concatenation with user input (N3, A4, A9)
  4. XSS -- correct encoding in VF; no innerHTML in LWC (N5, A5, A6)
  5. Credentials -- no hardcoded secrets; use Named/External Credentials (N6, A7)
  6. Logging -- no sensitive data in debug statements (N7)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.