SalesBleed is fixed, and nothing in your vulnerability scanner will ever tell you it existed. Zenity Labs showed that an anonymous stranger could type instructions into a Salesforce Web-to-Lead form, wait for a sales rep to ask Agentforce about new leads, and walk away with company names and deal sizes from the Accounts table — no login, no click. Salesforce patched the redaction bypass server-side and no CVE was issued. What Salesforce did not patch, because it cannot, is the pattern: an agent that reads public input, can query sensitive records, and can emit a link that something will fetch. That combination is a configuration decision, and it is yours.
The disclosure landed on September 24, 2026, when Zenity Labs published SalesBleed, and SecurityWeek and Infosecurity Magazine picked it up a day later. It hit the exact workflow Salesforce sells Agentforce for: triaging inbound leads.
How Did SalesBleed Steal CRM Data Without a Click?
SalesBleed is a zero-click indirect prompt injection: the attacker plants instructions in a record, and the victim's own routine request makes the agent execute them. Zenity's write-up walks the chain step by step.
- Entry. The attacker submits a lead through a public, unauthenticated Web-to-Lead form, with hidden instructions in the text.
- Trigger. An employee asks something ordinary — Zenity's example is "check my latest leads and help me with the newest one."
- Execution. The injected text tells the agent to use the Query Records tool to read the Accounts table and pull company names and deal sizes.
- Exfiltration. The agent writes an HTML image tag whose URL carries that data as a subdomain. The chat surface renders the tag, the browser resolves the hostname, and the DNS lookup itself delivers the data to the attacker.
The victim, in Zenity's words, "does only one thing: they ask their own agent a normal question about their own leads."
The part that should worry a platform owner is step three. The research agent had a subagent with read access to both Leads and Accounts, "which is how the default General CRM subagent ships," according to Zenity. The proof of concept took deal sizes, but Zenity is explicit that "the injection could have asked for anything the subagent's Query Records tool can reach" — accounts, contacts, other CRM records. Nobody escalated privilege. The agent used exactly the access it was given.
What Were the Three SalesBleed Flaws?
SalesBleed was three separate findings, two exfiltration paths and one abuse of a write action, as SecurityWeek summarised:
| # | Flaw | What it did | Egress path |
|---|---|---|---|
| 1 | Trusted URLs bypass via image tag | Exfiltrated Leads and Accounts data with no user action | DNS lookup when the chat UI rendered an <img> |
| 2 | Trusted URLs bypass via Slack preview | Same exfiltration for agents published to Slack | Slack's own crawler fetching the link to build a preview |
| 3 | Slack reply action abuse | Made the agent post phishing messages into internal Slack threads | Not exfiltration — impersonation from inside |
The first two share a root cause. Salesforce's Trusted URLs control is supposed to replace any non-allowlisted link in agent output. Zenity found two gaps: the redactor recognised only a fixed set of top-level domains, so a .fun domain sailed through, and the redactor and the renderer disagreed about where a URL ends, so curly braces and square brackets split the difference. A string like https://random_string.oast.fun/{email} looked malformed to the redactor and perfectly usable to the browser.
The second flaw is the one to sit with. "Slack automatically turns raw URLs into previews, and to build a preview it just crawls a link," Zenity wrote. That fetch happens on Slack's infrastructure, not your network — your DNS filtering and proxy logs never see it.
The third flaw, detailed in Zenity's companion post, hit the Reply to a Slack Thread action, which had neither user confirmation nor attribution of who invoked it. A poisoned lead could make the agent post a phishing link into an internal channel, dressed up behind markdown text. As Zenity put it to SecurityWeek, employees "receive a message from a trusted system already operating inside their workplace rather than from an unfamiliar outside sender."
Why Is There No CVE for SalesBleed?
There is no CVE because the flaw lived in Salesforce's hosted service, and CVEs track software customers install and patch. Neither Zenity's posts nor the trade coverage cite one. That is not an oversight — it is how every multi-tenant SaaS AI fix works. When Noma Security disclosed ForcedLeak against the same Agentforce and the same Web-to-Lead form a year earlier, The Register reported that the flaw "doesn't require a CVE because it's not related to a software upgrade."
For a CISO, the consequence is procedural. Your vulnerability management programme is keyed to CVE IDs. A finding with no ID, no customer action and no version number never enters the queue, never gets an owner and never appears in the quarterly risk report. You were exposed from whenever you enabled the agent until the fix, and your records will show nothing.
The timeline is also longer than the headlines suggest. Zenity's disclosure log has the report on June 1, 2026, Salesforce confirming fixes on August 18 and Zenity verifying the Trusted URLs patch on August 19. The Slack action fixes ran longer: Zenity's second post records attribution fixed August 20, the confirmation requirement still in development on August 25, and all fixes completed on September 21. SecurityWeek's line that all three were addressed by August 19 does not match Zenity's own log. The researcher's dated record is the one to put in your register.
Is This the First Time Agentforce Leaked Through Web-to-Lead?
No — SalesBleed is the second disclosed exfiltration chain through the same front door, and the first fix is what SalesBleed bypassed. In 2025, Noma Security's ForcedLeak used the Web-to-Lead description field, with its 42,000-character limit, to inject instructions, then exfiltrated through my-salesforce-cms.com — a domain on Salesforce's allowlist that had expired and that the researchers bought for $5. Noma scored it CVSS 9.4. Salesforce's response, per Noma, was "Trusted URLs Enforcement for Agentforce & Einstein AI," live September 8, 2025.
A year on, SalesBleed defeated that enforcement with an unlisted TLD and a bracket. This is the honest lesson. Output redaction is a filter written against the attacker's creativity, and it loses on a long enough timeline. Zenity says as much: "output redaction can sometimes miss," and this class of bug "isn't Salesforce-specific."
To steel-man Salesforce: it confirmed the report the next day, patched without customer action, re-tested with the researchers, and changed insecure Slack defaults rather than just documenting them. That is a good response to a disclosure. It is also the wrong thing to base your controls on, because the next bypass is already somebody's research project.
What Is the Real Fix for CRM Agent Prompt Injection?
The real fix is to never put all three ingredients in one agent. Simon Willison named it the "lethal trifecta" in June 2025: access to private data, exposure to untrusted content, and the ability to communicate externally. Zenity's version is the same idea in CRM terms: "Any agent that reads records submitted by external sources, renders links or images back to a user, and also holds tool access to sensitive data, has the same three ingredients sitting in the same place."
A prompt injection detector such as Lakera reduces how often the attack lands. Removing one leg of the trifecta decides whether it can land at all. For a lead-triage agent, all three legs are removable at acceptable cost:
- Untrusted input. Web-to-Lead, Web-to-Case, email-to-case and chat transcripts are all anonymous public input. reCAPTCHA stops bots; it does nothing against a human pasting a payload.
- Sensitive reads. A lead-triage agent needs Leads. It rarely needs the Accounts table with opportunity amounts. The default General CRM subagent grants both.
- Egress. Rendered images, clickable links and Slack previews are each an outbound request someone else's machine makes on your behalf.
Slack's own documentation is blunt about the last one: "By default, we unfurl all links in any messages posted by users and Slack apps." The unfurl_links and unfurl_media flags on chat.postMessage turn that off per message. Johann Rehberger flagged unfurling as an LLM exfiltration channel in April 2024 and recommended exactly that. For any bot that posts model output into Slack — Agentforce or your own — that is a two-line change.
What Should Salesforce Platform Owners Do Now?
Treat SalesBleed as a configuration audit, not a closed ticket. Salesforce fixed the bypass; the design choices that made the bypass valuable are in your org.
This Week:
- List every Agentforce agent that can see an externally created record. For each, write down which subagents it has and whether any of them is the default General CRM subagent. If an agent reads Web-to-Lead or Web-to-Case records and can also query Accounts or Opportunities, that is your trifecta — flag it.
- Log SalesBleed in your risk register as a vendor-side finding with the June 1 – September 21, 2026 exposure window and "no CVE, vendor-remediated" as the status. Do the same retroactively for ForcedLeak. You now have a record that exists outside the CVE feed.
- Check every write action that posts to Slack and confirm user confirmation is switched on. Zenity's warning is that "all it takes for the user confirmation requirement to be disabled is a single click of a button."
This Month:
- Replace the default subagent on lead-facing agents with a custom one whose Query Records scope covers Leads and nothing else, and have your Salesforce admin show you the permission set, not describe it.
- Prune your Trusted URLs list — remove every domain you cannot name an owner for, and check registration on the rest. ForcedLeak ran through an expired one.
- Turn off unfurling on every bot that posts LLM output to Slack, including in-house ones, by setting
unfurl_linksandunfurl_mediato false. - Run the Zenity chain yourself in a sandbox org: submit a test lead with an instruction to query Accounts and emit an image link to a domain you control, then ask the agent about new leads. If your DNS log lights up, you have work to do.
Before Renewal:
- Ask Salesforce for a written disclosure commitment for Agentforce fixes — the date of each AI-layer security fix and the affected window — since no CVE will ever carry it. Put the same question to every vendor whose agent reads your data.
The Bottom Line
The last decade taught security teams that SaaS meant the vendor patches and you configure. AI agents keep that split and raise the stakes on the configuration half. Salesforce has now fixed two Web-to-Lead exfiltration chains in twelve months, and both times the patch was to the filter that stood between an over-privileged agent and the internet. The filter will be bypassed again — it is the part of the system built to be clever.
The part built to be boring is which records an agent can read and where its output can go. That half never gets a CVE. It only gets an owner if you assign one.
Continue Reading
- Capsule Security: Why Copilot and Agentforce Both Leaked
- Agent Authorization: Standing Privilege Is the Whole Problem
- Antigravity's Allowlist Isn't Honored. Use Your Proxy.
- Claude Reads the Whole Channel Now. Invites Are IAM.
- NeMo Guardrails vs Guardrails AI vs Lakera: Buy the Detector
- Dreamforce 2026 Shipped Agent Operations, Not the Headline Model
- AI Vendor Security Review: 6 Questions That Change the Answer
