Apex security firewall for AI agents
The enforcement layer between AI agents and your Salesforce data.
Agentforce, MCP-connected assistants, and custom LLM integrations all end up calling the same Apex actions. AgentGuard wraps them in one line and treats every agent-issued call as untrusted input until it clears five gates — schema, access, rate, rollback, audit.
The problem
Three failure modes stop security teams from saying yes
Existing Salesforce controls operate at other layers — the Einstein Trust Layer governs prompts, Agentforce Command Center reports outcomes after the fact. Neither enforces anything at the moment an Apex action actually executes.
Prompt injection
An instruction hidden in a record, email, or knowledge article causes an agent to issue an action nobody asked for.
CRUD/FLS bypass
Apex invocables run in system context by default — an agent reads or mutates fields its requesting user was never permissioned to touch.
Unaudited mutation
A misbehaving agent fires DML in a loop with no throttle, no rollback boundary, and no real-time record of what it did.
How it works
Every wrapped call passes through the same chain — there is no bypass path
Policies are declarative. A Guard_Policy__mdt record per action defines
schema contracts, rate budgets, allowed profiles/permission sets, and record ceilings — tuned without an
Apex deployment.
SchemaValidator
Validates the raw payload against the policy's declared JSON schema contract before anything else runs. Unknown keys, missing required fields, and type mismatches are rejected outright.
Defends against — Tampering: a payload reshaped into a bulk or out-of-contract mutation.
AccessGate
Evaluates CRUD/FLS in the real running-user context with
WITH USER_MODE and
Security.stripInaccessible() — never an elevated or claimed context.
Enforces profile and permission-set scoping.
Defends against — Spoofing & information disclosure: an agent claiming higher privilege, or reading fields the user can't see.
RateLimiter
Sliding-window budget per user, per action, backed by Platform Cache. Falls back to allow-and-flag if the cache partition is unavailable, so a cache outage degrades to logging rather than an outright deny.
Defends against — Denial of service: a flooded action exhausting downstream limits.
RollbackGuard
Opens a Savepoint and enforces a hard ceiling on records-per-call before your business logic runs. Any exception mid-execution rolls back atomically — nothing partial survives.
Defends against — Elevation of privilege: a partial bulk mutation leaving inconsistent state.
AuditPublisher
Every decision from every gate — ALLOW, BLOCK, or THROTTLED — publishes as an
AgentGuard_Audit__e Platform Event, outside the transaction boundary, so
the record survives even a rollback.
Defends against — Repudiation: a destructive call with no record of what happened.
Design guarantees
Restrictive by default, fails closed, one line to integrate
Fail closed
Any exception inside a gate is a BLOCK, never an ALLOW.
Restrictive by default
Every policy field defaults to its most restrictive safe value; nothing is permitted unless explicitly configured.
Running-user context only
Access checks run WITH USER_MODE against the real user — never an elevated
or claimed context.
Audit survives rollback
Decisions publish as Platform Events, outside the transaction's rollback boundary.
One-line integration
"Integrated correctly" and "integrated at all" are the same thing — one facade, per-gate toggles via policy metadata.
Quick start
Set up in four steps
Authenticate & scratch org
sf org login web \ --set-default-dev-hub sf org create scratch \ --alias agentguard-dev
Deploy metadata
sf project deploy start \ --target-org agentguard-dev
Create the cache partition
Setup → Platform Cache → New Partition → name: AgentGuard
Run the test suite
sf apex run test \ --code-coverage \ --wait 30
Wrap an existing invocable
One check before your business logic runs — validated, access-checked, throttled, inside a Savepoint boundary, and audited.
Full walkthrough with troubleshooting and a worked example: the Getting Started section of the guide.
@InvocableMethod(label='Update Account Territory')
public static List<Result> execute(List<Request> requests) {
GuardResult check = AgentGuard.wrap(
'UpdateAccountTerritory',
JSON.serialize(requests)
);
if (!check.isAllowed) {
throw new AgentGuard.BlockedException(
check.reason, check.decision, check.gateName
);
}
return YourBusinessLogic.execute(requests); // your existing code, unchanged
}
Threat coverage
Mapped to STRIDE, not marketing categories
| STRIDE category | Mitigating component |
|---|---|
| Spoofing — agent claims a higher-privileged context | AccessGate evaluates against the real running-user context only |
| Tampering — injected payload reshaped into bulk / out-of-contract mutation |
SchemaValidator rejects payloads violating the declared contract
|
| Repudiation — destructive call with no record |
AuditPublisher logs every decision with actor, payload hash, timestamp
|
| Information disclosure — fields the user cannot see | AccessGate strips/blocks inaccessible fields on read paths |
| Denial of service — flooded actions exhausting limits | RateLimiter sliding-window per-agent/per-action budgets |
| Elevation of privilege — partial bulk mutations leave inconsistent state | RollbackGuard Savepoint boundary and record ceiling |
Full model, explicit non-goals, and the maintained risk register live in the Threat Model & Compliance section of the guide.
Honest scope
What AgentGuard SF does not do
- Not a prompt-level control. It does not mask data sent to an LLM — pair it with the Einstein Trust Layer at the prompt boundary.
-
Not a scanner. It governs only calls that opt in via
AgentGuard.wrap(). - No semantic injection detection. Enforcement is structural, not a content classifier.
- Not durable rate-limit state. Platform Cache counters can reset on eviction; pair with Shield Event Monitoring for a durable audit trail.
- No cross-org policy sync in v1. Policies deploy per-org like any metadata.
Read the full guide before your first deploy
What it is, how to set it up, and how to use it — end to end.