Skip to main content

Agentforce and AI

These checks read Agentforce metadata (genAiAgents/, genAiPlugins/, genAiFunctions/, genAiPromptTemplates/ and the MDAPI layout) and match each agent action to the Apex class it runs.

vulkro-sf scan ./force-app # security checks
vulkro-sf antipatterns ./force-app # AP-061 to AP-070

Security checks (scan)​

CheckWhat it finds
ForcedLeak (agentforce-action-without-sharing-class)A GenAiFunction whose <invocationTarget> is an Apex class declared without sharing or with no sharing keyword. Anyone who can prompt the agent can read records they are not entitled to see. Emitted only when both files are present and the match is unambiguous.
Agent inventory (agentforce-agent-present)Lists every GenAiAgent, GenAiPlugin and GenAiFunction at informational severity. Not a finding by itself; it does not count toward the exit code.
MCP tools (SF-MCP-000 to SF-MCP-003)MCP servers and tools wired into the org. See LLM and AI response security.

Anti-pattern checks (antipatterns)​

Rule IDWhat it finds
AP-061An @InvocableMethod / @AuraEnabled action returns a PII free-text field (such as Lead.Description, Case.Description) to the agent with no sanitizer (String.escapeHtml4, String.stripHtml, a length bound, a Pattern.matches allowlist or Security.stripInaccessible).
AP-062A Trusted URL uses a wildcard Salesforce removed from the default Agentforce allowlist (*.salesforce.com, *.force.com, *.cloudforce.com, *.visualforce.com, *.lightning.com and siblings).
AP-063A Trusted URL grants a CSP directive (img-src, connect-src, frame-src, script-src, style-src, media-src) to a host that is not org-owned.
AP-064An agent-action class over a PII object declares neither with sharing nor without sharing, so it runs in system mode.
AP-066A planner mentions a PII object (Contact, Lead, Case, Account) but wires no customer-verification action.
AP-067A planner uses SvcCopilotTmpl__ServiceCustomerVerification.VerifyCustomer without the attributeMappings for isVerified and customerId.
AP-068A topic's <masterLabel>, <description> or <scope> is shorter than the minimum (5 / 15 / 15 words by default).
AP-069A planner has more topics than the threshold (default 15), which hurts routing accuracy.
AP-070An agent, topic or action has no *.aiTestCase-meta.xml, *.botTest-meta.xml or *.agentTest-meta.xml test.

The PII field list, wildcard list and thresholds come from the signed rules bundle.

Example​

Non-compliant: the agent action runs a without sharing class.

<!-- LeadLookup.genAiFunction-meta.xml -->
<GenAiFunction xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>Lead Lookup</masterLabel>
<invocationTarget>LeadLookupAction</invocationTarget>
<invocationTargetType>apex</invocationTargetType>
</GenAiFunction>
public without sharing class LeadLookupAction {
@InvocableMethod
public static List<Result> run(List<Request> requests) { /* SELECT ... FROM Lead */ }
}

Compliant: declare with sharing and query WITH USER_MODE so CRUD, FLS and sharing apply to the caller.

public with sharing class LeadLookupAction {
@InvocableMethod
public static List<Result> run(List<Request> requests) {
// SELECT Id, Name, Email FROM Lead WHERE Status = :r.status WITH USER_MODE
}
}

See also: Agentforce guardrails, Cross-method engine, Breach-class map