The Agentforce agent user: which user your agent runs as, and why it can't update the record
The most common Agentforce failure isn't the model — it's a permission. Whether an agent runs as the logged-in employee or as its own service-agent user decides everything it can see and do, and a missing field-level permission is why 'the agent can't update the record.' Here's the running-user model, the CRUD/FLS/sharing it inherits, the guest-user surface, and how to scope an agent to least privilege.
Here is the support ticket every Agentforce team eventually files: the agent understood the request, picked the right action, filled in the fields — and then failed to save the record. The transcript looks fine. The topic classification looks fine. The model did everything right. And the whole thing died on a permission the agent never had.
This is the single most common way a working Agentforce demo turns into a broken production agent, and it is almost never a model problem. An agent doesn’t act with magic powers; it acts as a Salesforce user, and it is bound by exactly the same object permissions, field-level security, and sharing that bind any other user. The question that decides what your agent can do isn’t “how good is the prompt” — it’s which user is this agent running as, and what is that user allowed to touch. Get that wrong and no amount of instruction-tuning will save you. Get it right and most of the “the agent hallucinated / refused / failed silently” tickets never get written.
This post is the permission model underneath Agentforce: which user an agent runs as in each deployment mode, what that user inherits, the guest-user surface you open the day you put an agent on a public website, how custom Apex actions can quietly bypass the whole thing, and how to scope an agent to least privilege without starving it.
The one question: which user is the agent?
Agentforce agents don’t run in a vacuum. Every action an agent takes — a SOQL read, a record update, a Flow, an Apex call — executes in the security context of a specific Salesforce user, and which user that is depends on the kind of agent you built.
Employee agents run as the person using them. An internal, authenticated agent — the kind an employee opens inside Salesforce to summarize a record, draft an email, or update an opportunity — operates in the security context of the logged-in user. It inherits that user’s profile, permission sets, roles, field-level security, and record access. The practical consequence is the one people don’t expect: the same agent shows different data to different people. A rep and their manager can open the identical employee agent and see different records, because the agent is only ever as powerful as the human driving it. That’s a feature — it means an employee agent can’t become a privilege-escalation path around your existing sharing model — but it also means “the agent can’t see that account” is often the correct, working behavior, not a bug.
Service agents run as their own dedicated user. A customer-facing agent — the Agentforce Service Agent you put on a website, a help center, or a messaging channel — does not run as the customer. Customers aren’t Salesforce users; they can’t be. Instead the service agent executes as a dedicated agent user with its own profile and permission sets, provisioned specifically for the agent. Everything that agent is allowed to read or write is defined on that user, once, centrally — which is powerful and dangerous in equal measure, because a customer-facing agent’s permissions apply to every anonymous person who talks to it.
That distinction is the whole ballgame. For an employee agent, you audit permissions per human. For a service agent, you audit one user — the agent user — and you assume the worst possible visitor is behind it.
An employee agent is as powerful as the person using it. A service agent is as powerful as the one user you configured — for everyone who ever talks to it. Design the second one as if an adversary is on the other end, because eventually one will be.
What the agent user actually inherits
Whichever mode you’re in, the running user carries the ordinary Salesforce access-control stack, and an agent’s actions are checked against all of it:
- Object permissions (CRUD). If the running user can’t Create on Case, the agent can’t open a case. If it can’t Edit on Opportunity, the agent can’t update the stage. These are the coarsest gate and the first thing to check.
- Field-Level Security (FLS). This is the one that bites. An action can have full object access and still fail — or silently drop a value — because the running user lacks Edit (or even Read) on a single field the action writes. “The agent understood everything and still couldn’t save the record” is, nine times out of ten, an FLS miss on one field.
- Sharing and record access. Object and field permissions decide which fields on which object types; sharing decides which specific records. An agent running as a user with a restrictive role and private org-wide defaults simply won’t see records outside that user’s share, exactly as a human wouldn’t.
The reason this surfaces so violently with agents, and not with the same permissions on a screen, is that an agent has no workaround. A human who hits a locked field edits around it, asks a colleague, or retries on another screen. An agent either has the permission or it fails — often with a generic error the model then tries to narrate its way around, which is how a permission gap becomes a “hallucination.” Agentforce actions require the running user to have access to every object, field, and record the action might touch, and a single missing grant is enough to break the whole action. There’s no partial credit.
This is also why the guidance you’ll hear from every seasoned admin is move from profiles to permission sets before you go anywhere near Agentforce. Profiles are coarse and shared; permission sets let you assemble exactly the object and field grants an agent user needs and nothing more, and revoke them just as precisely. An org still leaning on fat profiles will find agent permissioning nearly impossible to reason about.
Setting up a service agent user, concretely
For an Agentforce Service Agent, the setup has a shape worth knowing because it’s where teams get stuck. Beyond the base license, you assign the agent user the platform permission sets that turn a user into a functioning service agent — in current orgs these are named along the lines of Agentforce Service Agent User and Agentforce Service Agent Permissions — and then you add your own permission set granting the specific object and field access the agent’s topics and actions need.
That second, custom permission set is the one you actually design. If the agent creates cases from contacts, it needs Read on the Contact fields it reads and Create/Edit on the Case fields it writes — and nothing else. The temptation is to clone a broad internal profile to “make the errors go away.” Don’t. You are defining the blast radius of an unauthenticated, always-on user that talks to strangers. Grant the fields the actions touch; leave the rest locked.
A discipline that pays off: build the agent’s permission set from the actions inward. List every action the agent can invoke, list every object and field each action reads or writes, and grant exactly that set. When you add a topic or an action later, you extend the permission set deliberately — you don’t discover the requirement as a production failure. This is the same least-privilege posture we argue for when governing an agent fleet before it governs you: the agent’s identity is a security boundary, and boundaries are cheaper to draw up front than to reconstruct after an incident.
The guest-user surface nobody budgets for
The day you put a service agent on a public, unauthenticated page, you’ve done more than deploy an agent — you’ve exposed whatever that agent’s user can reach to anyone on the internet. Salesforce provides a specific configuration path for this (setting up Agentforce for guest users), and the reason it’s a distinct, deliberate step is that the guest surface is where over-permissioning turns into data exposure.
Two things deserve real scrutiny here. First, the agent user’s read access is now an anonymous read surface. Anything the agent can retrieve to ground an answer, a sufficiently clever visitor can try to coax it into surfacing. Scope the agent’s grounding and its object access to precisely the public-safe slice — never the internal knowledge base, never fields that carry PII you wouldn’t print on the homepage. Second, the inputs are hostile by default. A public agent’s every message is untrusted, which means this is exactly the deployment where prompt-injection and least-privilege discipline stop being theoretical. The mitigation isn’t a cleverer system prompt; it’s a small, tightly-scoped agent user whose permissions make the worst-case retrieval boring.
If a visitor authenticates — logs into a community or portal — the identity picture changes, and you can pass verified context into the session rather than treating everyone as an anonymous guest. But the default posture for a public agent is: assume the guest user is the attacker, and permission accordingly.
Where custom Apex actions quietly break the model
Here’s the trap that catches strong engineering teams. Everything above — CRUD, FLS, sharing enforced against the running user — is how the platform behaves by default. But the moment an agent calls a custom Apex action, you’re in code, and Apex can execute in system context — historically the default — which means it can bypass the running user’s FLS and object permissions unless you enforce user mode. An Apex action that naively does insert record; in system context will happily write fields the agent user could never edit through the platform. Convenient in the moment; a hole in your permission model in production.
The fix is to run Apex actions in the user’s mode so the database operations are checked against the running user, the same way the declarative actions are. Modern Apex gives you clean syntax for exactly this:
public with sharing class UpdateCaseStatusAction {
@InvocableMethod(label='Update Case Status')
public static void run(List<Request> requests) {
List<Case> toUpdate = new List<Case>();
for (Request r : requests) {
// WITH USER_MODE enforces the running user's CRUD, FLS, and sharing
Case c = [
SELECT Id, Status
FROM Case
WHERE Id = :r.caseId
WITH USER_MODE
];
c.Status = r.newStatus;
toUpdate.add(c);
}
// 'as user' applies USER_MODE to the DML — FLS and CRUD are enforced
update as user toUpdate;
}
public class Request {
@InvocableVariable(required=true) public Id caseId;
@InvocableVariable(required=true) public String newStatus;
}
}
Three things are doing the work here. The class is declared with sharing, so record-level sharing is respected (a bare class, or one marked without sharing, ignores it). The SOQL carries WITH USER_MODE, so the query enforces the running user’s object and field permissions and sharing. And the DML uses update as user, applying the same user-mode enforcement to the write — so a field the agent user can’t edit throws instead of silently writing. If you’re on an older pattern, WITH SECURITY_ENFORCED on the SOQL and Security.stripInaccessible() around DML get you part of the way, but USER_MODE and the as user / as system keywords are the current, complete answer.
The rule of thumb: a custom Apex action should enforce the same permissions the platform would. If you deliberately need elevated access — a system operation the agent user genuinely shouldn’t hold directly — do it consciously, in a narrowly-scoped class, and treat that class as a privileged component you review like any other. What you don’t want is to accidentally hand a customer-facing agent system-context write access because a developer reached for the default. This is the security dimension of the same lesson we drew about custom Apex actions: the action is real code with real consequences, and its permission posture is part of its design, not an afterthought.
Two layers people conflate: CRM permissions and Data 360 access
One clarification that saves a lot of confusion. Everything in this post is about core CRM object permissions — CRUD, FLS, and sharing on Accounts, Cases, Opportunities, custom objects. If your agent is grounded on Data 360 (the platform formerly called Data Cloud), that grounding rides on a separate access-control layer. Whether the agent can retrieve a given Data Cloud object is governed by Data 360’s own governance and sharing model, not by the CRM permission set on the agent user.
So a complete agent has to pass two independent reviews: “can the running user act on the CRM records this action touches?” and “can the agent retrieve the Data 360 data it grounds on, scoped to what this user is allowed to see?” They fail differently and you fix them in different places. Treat them as one and you’ll spend a day granting CRM field access to fix a problem that lived in Data Cloud, or vice versa.
A pre-launch permission checklist
Before a service agent goes live, walk this list — it’s the cheapest incident you’ll ever avoid:
- Enumerate the agent user’s grants. For a service agent, list every object and field permission on the agent user and justify each one against a real action. Anything you can’t justify, remove.
- Trace every action to its permissions. For each action the agent can invoke, confirm the running user has CRUD on the objects and FLS on the specific fields it reads and writes — reads included, because an action can’t act on a field it can’t see.
- Audit the Apex. Any custom Apex action uses
with sharingandUSER_MODE/as userunless it has a deliberate, reviewed reason not to. - Assume the hostile guest. For any public deployment, review the agent user’s read surface as if an anonymous attacker is driving it, and confirm no PII or internal knowledge is reachable that shouldn’t be.
- Separate the Data 360 review. Confirm grounding access is scoped in Data Cloud governance, independently of the CRM permission set.
- Test as the agent, not as an admin. The classic mistake is verifying an agent while logged in as a System Administrator who can see everything. Test with the actual agent user’s permissions, the way debugging a production agent demands — the failures you’re hunting only appear under the real, restricted identity.
None of this is exotic Agentforce knowledge; it’s the ordinary Salesforce security model, applied to a user that happens to be an AI. That’s the reframe worth internalizing. Your agent isn’t a new kind of thing that needs a new kind of security. It’s a user — and it deserves the same least-privilege scrutiny you’d give any user who could touch a customer record, plus a little more, because this one never gets tired, never gets suspicious, and talks to whoever shows up.
The takeaway
The permission that breaks your agent is hiding in plain sight. Decide first which user the agent runs as — the logged-in employee for an internal agent, a dedicated agent user for a customer-facing one — because that single fact determines everything downstream. Then remember the running user carries the full stack: object CRUD, field-level security, and sharing, and an agent has no workaround when one is missing, which is why a lone unchecked field is the usual cause of “the agent can’t update the record.” Move to permission sets so you can scope the agent user precisely; build that scope from the actions inward to least privilege; treat the guest-user surface of any public agent as a hostile read surface; and make custom Apex actions enforce the same permissions the platform would, with with sharing and USER_MODE. Keep the Data 360 grounding review separate from the CRM permission review. Do that, and the most common Agentforce failure mode simply stops happening — because you designed the agent’s identity before it ever met a customer. Getting that identity right up front is a core part of our Agentforce work.
Understanding the basics
Which user does an Agentforce agent run as?
It depends on the type. An employee-facing agent runs in the security context of the logged-in user, inheriting that person’s profile, permission sets, field-level security, and record access — so the same agent shows different data to different users. A customer-facing service agent runs as its own dedicated agent user with its own profile and permission sets, because customers aren’t Salesforce users; that one agent user’s permissions apply to everyone who talks to the agent, which is why a public service agent has to be scoped as tightly as possible.
Why can’t my Agentforce agent update a record?
Almost always because the running user lacks a permission the action needs — most commonly Edit access on a single field via field-level security, or Create/Edit object permission (CRUD) on the target object, or record access through sharing. Agentforce actions require the running user to have access to every object, field, and record the action touches, and there’s no partial success: one missing grant fails the whole action, often with a generic error the model then narrates unhelpfully. Check the agent user’s CRUD and FLS on exactly the fields the action reads and writes.
Do custom Apex actions respect the agent’s permissions?
Not unless you make them. Apex can run in system context, where it bypasses the running user’s CRUD and field-level security, so you enforce user mode explicitly. Declare the class with sharing, run SOQL with WITH USER_MODE, and perform DML with as user (or use WITH SECURITY_ENFORCED and Security.stripInaccessible() on older patterns). Without this, a custom action can quietly grant a customer-facing agent write access to fields its user could never edit through the platform — a real hole in your permission model.
Is Data 360 access the same as the agent’s CRM permissions?
No — they’re two separate layers. The agent user’s CRM object permissions (CRUD, FLS, sharing) govern what it can do with Salesforce records. What the agent can retrieve from Data 360 for grounding is controlled by Data Cloud’s own governance and sharing model. A complete agent has to pass both reviews independently, and they fail and get fixed in different places, so don’t try to solve a Data Cloud access problem by granting CRM field permissions.
Standing up an Agentforce agent and hitting permission errors you can’t trace — or worried a public agent can reach more than it should? Talk to us. Scoping an agent user to least privilege, and making its actions enforce the permissions you actually intend, is a normal part of getting an agent safely to production.
Keep reading
All insights
Agentforce Contact Center: what changes when Salesforce owns the phone line, not just the CRM
AI agents for wealth management: where the agent preps the meeting, and where the advisor still gives the advice
Testing Agentforce agents in CI/CD: AiEvaluationDefinition, the CLI, and the pipeline the Testing Center can't give you