Discussions around AI agent security tend to get polarized quickly. One side assumes a vendor's trust layer makes autonomous workflows safe out of the box, while the other treats any demonstrated vulnerability as proof that putting agents inside a CRM is fundamentally unworkable. The "SalesBleed" research shows that both views miss the real mechanics.
The researchers at Zenity did not bypass Salesforce's multi-tenant boundary or break field-level security. Instead, they showed how untrusted text stored inside an ordinary CRM record could steer an agent to pull data it already had permission to view, and how gaps in URL parsing and default Slack actions allowed that data to leave the organization via DNS lookups.
Agent security usually comes down to practical identity and authorization hygiene: which identity the agent runs as, what records and fields that identity can touch, which tools it can invoke, and how downstream clients render the agent's output.
The short version
- A public Web-to-Lead form could store hidden prompt-injection instructions inside an ordinary lead record.
- When an employee later asked Agentforce a routine question about recent leads, the agent evaluated the stored text as instructions. That steered it to query account data it was already permitted to read.
- In the tested configuration, a Trusted URLs parsing quirk allowed extracted account data to be embedded in an external hostname. Rendering an image or triggering a Slack link preview forced a DNS lookup to that hostname, carrying the data out without requiring anyone to click a link.
- A related issue in the default Slack Knowledge subagent allowed
Reply to a Slack Threadto post messages without explicit user confirmation or invoker attribution. - Salesforce and Zenity confirmed that the specific platform-side issues were patched before public disclosure. The fixes closed those specific paths, but configuring least-privilege permissions and narrow tool scopes is still up to individual org admins.
The disclosure timeline
Zenity reported its findings to Salesforce on June 1, 2026. Salesforce confirmed a fix for the Trusted URLs issue on August 18, and Zenity verified it on August 19. Invoker attribution for the Slack action was added on August 20. Zenity confirmed all reported fixes by September 21 and published its research on September 24.
SalesBleed was a coordinated disclosure where the vendor addressed the demonstrated platform bugs prior to publication. The research serves as a useful proof of concept and vulnerability chain, rather than evidence of an active, widespread customer breach.
How the attack worked
The exfiltration path linked untrusted user input, existing agent permissions, and an automated DNS lookup triggered by downstream rendering.
An attacker submitted a lead. Web-to-Lead forms are unauthenticated by design. Zenity placed prompt-injection instructions inside an ordinary free-text field. The attacker did not need Salesforce credentials.
The instructions sat in the database. The payload did not need to run immediately. It waited until an employee asked Agentforce a normal question, like asking for a summary of recent inbound leads.
The agent followed the injected instructions. In Zenity's test environment, the General CRM subagent had access to the
Query Recordstool across both Leads and Accounts. The injected prompt steered the agent away from the lead and told it to query account records, including company names and deal sizes. The agent did not need elevated privileges; it simply used the permissions it already held.The data was added to an external hostname. The agent's generated response included an external URL containing the queried CRM data encoded into a subdomain. Before the fix, Trusted URLs redaction and downstream rendering surfaces handled certain edge-case URLs differently, particularly around less common top-level domains and trailing characters. The redactor treated the string as text, while the rendering client parsed it as a live URL.
A client-side renderer triggered a DNS lookup. When an HTML image tag or a Slack link preview tried to render the URL, the client attempted to resolve the attacker-controlled hostname. That DNS query transmitted the encoded data directly to the attacker's nameserver before any HTTP connection completed. Blocking HTTP traffic at a firewall would not stop a DNS query that had already finished.
There was also a secondary Slack phishing vector. The Reply to a Slack Thread action in the default Slack Knowledge subagent did not require confirmation or display who invoked the agent. An adversarial lead could prompt the agent to post misleading messages into internal Slack channels under the guise of an official bot. Salesforce updated the default confirmation and attribution behavior for that action during the remediation window.
What "zero-click" meant here
"Zero-click" does not mean no one in the company took an action. An employee still had to ask the agent an ordinary question that caused it to pull the poisoned lead into its context window.
The zero-click aspect applies specifically to the exfiltration step: the employee did not need to click a link, open an attachment, or approve an unexpected pop-up. Once the agent generated the crafted output, the rendering layer triggered the DNS resolution on its own.
What the research did and did not show
The research did not demonstrate a cross-tenant exploit or a bypass of Salesforce's core permission model. The agent accessed records it had legitimate rights to see. The underlying problem was that untrusted data inside a business record could steer authorized tools toward an unintended query, and then route that data to an unapproved destination.
The public demonstration used Web-to-Lead as its entry point. Similar risks can apply to Email-to-Case, inbound support tickets, live chat transcripts, and uploaded documents, but those are related threat models rather than the specific setup documented in the report.
Additionally, "DNS-based exfiltration" is more accurate here than "DNS tunneling." The research showed data leaving via standard DNS lookup requests sent to an authoritative nameserver, rather than an interactive, two-way DNS tunnel.
What the Einstein Trust Layer actually covers
Salesforce documents the Einstein Trust Layer as a set of guardrails for generative features, including data retrieval controls, masking, prompt defenses, Trusted URLs, and audit logs. These tools help with specific parts of the workflow, but they do not serve as a complete authorization policy for agent tool execution.
- Secure grounding and Salesforce permissions: Salesforce designs grounding to follow the executing user's access controls, including object permissions, sharing rules, and field-level security. However, this does not fix an over-permissioned identity. If the identity can read an object, the agent can generally query it when asked.
- Zero Data Retention (ZDR): The ZDR agreement ensures external model providers like OpenAI or Azure do not retain prompts or use them for training. This is a vendor data privacy control, not an operational safety guardrail. It has no bearing on where an agent sends data during tool execution, and it does not stop Salesforce from storing prompt histories and audit logs internally in Data 360.
- Data masking: While the Trust Layer can mask recognizable patterns like credit card numbers or social security numbers in standard generative features, Salesforce documentation states that data masking is currently disabled for agents. Deployments should not rely on masking to hide sensitive values before an agent processes them.
- Prompt defense and injection detection: Semantic filters and system prompts help flag overt abuse, but they are probabilistic. A defensive prompt instruction is not a substitute for hard limits on what a tool can read or execute.
- Trusted URLs: This setting redacts unapproved external domains in agent outputs. It acts as an output filter rather than a network firewall, and the reported exploit showed that URL-parser discrepancies could let hostname-based lookups slip through. Salesforce has since corrected that parsing behavior.
- Audit and feedback: Logging prompts, model responses, and trust signals in Data Cloud gives visibility after an event occurs, but audit records do not block an unauthorized action while it is executing.
The permission trade-offs
Salesforce documentation notes that Agentforce works within standard access controls like licenses, profiles, permission sets, and sharing rules. An agent does not have automatic access to records outside its assigned context.
However, respecting permissions is not the same as having narrow permissions. In Zenity's test environment, the General CRM subagent had access to both Leads and Accounts through Query Records. That setup highlights the risk of broad tool configurations, rather than a failure of field-level security itself.
Runtime identities also vary depending on the setup:
- Employee-facing agents: In Lightning Experience, mobile apps, or Slack, these agents generally run under the permissions of the logged-in user.
- Service agents: Customer-facing agents often run under a dedicated Agent User, whose assigned profile and permission sets determine overall data access.
Checking the exact runtime principal is usually the best place to start when reviewing permissions.
A practical permission model for Agentforce
When setting up or auditing an agent, it helps to answer four basic questions:
- Who is the runtime principal? Check whether the agent runs as the individual employee, a dedicated service user, or an integration account.
- Which objects can it access? Remove access to objects the workflow does not need, and avoid broad administrative permissions like "View All" or "Modify All."
- Which fields and records are visible? Use field-level security to hide sensitive identifiers, financial details, or internal notes. Check that sharing rules limit records to the specific team or queue the agent supports.
- Which tools and destinations are reachable? Separate read tools from write tools, and review connected capabilities across Slack, email, Flow, and external APIs.
Broad query tools come with real operational trade-offs. Salesforce documents Query Records as retrieving searchable standard and custom objects based on user access. For agents processing public submissions, it is often safer to replace open-ended query actions with custom Apex actions or Flows that return only a specific set of fields for a given record ID.
When writing custom actions, Apex code should generally run in user mode (WITH USER_MODE) and enforce sharing rules (with sharing) so the agent cannot query data beyond its assigned rights.
Safer lead triage workflow
A safer workflow keeps unauthenticated inputs isolated from internal databases and outbound communication tools:
text
Public Web-to-Lead submission
↓
Lead-triage agent
- Reads only the incoming Lead record
- Categorizes or summarizes text
- Has no tool access to Accounts or Opportunities
- Has no outbound messaging or Slack capabilities
↓
Human review
↓
Downstream action agent
- Operates on sanitized, reviewed lead data
- Handles outbound communication through approved channels
- Requires explicit user confirmation and logs the invoker
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.