// hackerlogs
login+ register
Agentic AIPrompt InjectionLLM AppSecThreat BriefHigh

Salesforce Closed the Ticket in June. Slack's Confirm Landed in September.

Zenity's SalesBleed posts are dated 24 September. URL redaction was confirmed fixed on 19 August. The Slack thread reply required confirmation only on 21 September.

The short answer

On 24 September 2026 Zenity published SalesBleed, three Salesforce Agentforce flaws reported on 1 June. A public lead form could make an agent leak CRM fields and post in Slack as itself. Salesforce's URL redaction fix was confirmed on 19 August. Slack attribution landed on 20 August. Required confirmation on the thread reply was confirmed only on 21 September.

Key takeaways

  • Zenity Labs is the primary, in two posts dated 24 September. The Register ran the same day. Infosecurity Magazine followed on 25 September.
  • The entry was a public Web-to-Lead form. No Salesforce login. The default CRM subagent could already read both leads and accounts.
  • Trusted URLs was confirmed fixed on 19 August. Slack showed the invoker on 20 August. Confirmation on Reply to a Slack Thread waited until 21 September.
  • Salesforce closed the disclosures on 17 June while engineering was still working. A closed ticket is not a patched org.
  • The lead stays in the table after the fix. Zenity says one click can turn the new confirmation default back off.

On 24 September Zenity Labs published SalesBleed in two posts. A public Web-to-Lead form was enough to put instructions in front of a Salesforce Agentforce agent. Nobody needed a Salesforce login. The default General CRM subagent could already read leads and accounts, so the injection did not have to escalate. CRM fields left as a DNS lookup when the chat surface or Slack fetched a string the URL redactor had not classified as a URL. A second default, Reply to a Slack Thread, posted that kind of message with no confirmation and no name of the person who invoked it.

The Register carried it the same day. Infosecurity Magazine followed on 25 September, which is how it showed up in Google News. Hacker News did not lead with it. US X trends were television, golf, and football.

High High because a public form plus a default subagent was enough to read account fields and to speak in Slack as the agent. The chain Zenity retested is closed. The dates are not one date.

Three panels for SalesBleed: a public lead form into an agent that can read accounts, a June ticket close versus an August redaction fix and a September Slack confirmation, and the checks an org still has to make.

What Zenity actually reported.#

The first post is the data path. Companies leave Web-to-Lead open so strangers can submit leads. Those leads sit in a table the agent is asked to summarize. Zenity's case is an employee asking a routine question about the newest lead. The lead's contents are then in the agent's context. The same subagent's query tool could read the Accounts table, because that is how the default General CRM subagent ships. Zenity is explicit that this was not a privilege escalation. The grants were already there.

The exit did not need a click. Trusted URLs is supposed to strip untrusted links from the agent's reply before a person sees them. Zenity got a string through that layer which the chat client, or Slack's link preview, still tried to fetch. The fetch starts with DNS. By the time an HTTP control blocks the request, the name has already been looked up, and the fields were in the name. Zenity also notes that redaction runs after the model writes, so the model is not told that a line was removed. The lead remains in the table and can fire on the next review. Nothing in the product expires it.

The second post is the identity path. Agentforce ships Slack subagents, including a Slack Knowledge template, that can be added quickly. Send a Slack Direct Message, in Zenity's test, asked for confirmation and named the user who invoked it. Reply to a Slack Thread did neither. A lead, or an insider who can already chat with the agent, could have the agent answer a thread as itself. Recipients saw the agent, not the person or the form behind the request. The redaction gap mattered here too, because a link that should have been stripped could remain in that reply.

The package clock and the impact clock.#

There is no CVE in either post, and no customer build number. The package clock is a set of confirmation dates from Zenity, not a version you can pin in a lockfile.

Reported by email on 1 June. Salesforce confirmed on 2 June. A call on 16 June. Disclosures closed on 17 June, fix still underway. On 18 August Salesforce told Zenity the fixes were fully confirmed. On 19 August Zenity confirmed the specific Trusted URLs bypass. On 20 August the Slack reply showed the invoking user. On 25 August confirmation-by-default was still open, with Salesforce saying on 10 September that it was expected by 21 September. On 21 September Zenity tested all three and confirmed them. The posts are 24 September. The Register's account matches that last confirmation.

So the URL-redaction control has a package date of 19 August. The Slack write has two: a name on the message from 20 August, and a confirmation default from 21 September. Publishing on 24 September is after both. Using the June close, or even the August redaction date, as "Slack is fixed" is how a status report skips a month.

This is the disclosure-clock shape in the OpenAI Medicare notice: the event, the vendor's internal date, and the date a defender can act are not the same day. Here the defender's date is 24 September, and the last control inside the product was 21 September. Anyone who briefed "Salesforce closed it in June" briefed the wrong clock.

  1. Zenity reports all three issues to Salesforce. Salesforce confirms the next day.
  2. Salesforce closes the disclosures and says engineering is still working on a fix.
  3. Zenity confirms the Trusted URLs bypass is fixed. Salesforce had called the fixes complete on 18 August. Slack attribution follows on 20 August.
  4. Confirmation by default for Reply to a Slack Thread is still in progress. On 10 September Salesforce points at 21 September.
  5. Zenity confirms and tests all three fixes. The two posts publish on 24 September.

What this is not.#

It is not a headcount of breached tenants. Zenity does not publish a customer incident list. The finding is a default subagent, a public form, and a redaction layer that did not agree with the client that rendered the reply. Infosecurity's 25 September story matches that scope and the 18 August vendor fix for the redaction bypass.

It is not a patch for prompt injection. Salesforce hardened Trusted URLs and changed the Slack action's defaults. An agent that reads untrusted leads and can also read accounts still holds both grants. Zenity's point, and Infosecurity's, is that those three ingredients are not unique to Agentforce: outside data, a renderer that fetches what the model prints, and a tool that can see sensitive rows.

It is not one remediation date. The redaction bypass and the Slack confirmation default were five weeks apart. A program that marked the ticket done on 19 August left the write action without a confirmation default until 21 September.

It is also not a procedure you need to replay. The posts include the bypass. Checking the org does not require it.

What to do.#

  1. In each Agentforce org, confirm the behavior, not the blog date. Trusted URLs should match what Zenity retested on 19 August. Reply to a Slack Thread should require confirmation and should show the invoking user, which Zenity confirmed on 21 September and 20 August. Sandbox and production can differ. The vendor's confirmation is not your tenant's setting.
  2. Leave confirmation on. Zenity says a single click disables it, and once it is off the Slack path they described is available again. Treat that toggle as a control you review, not a default you assume survived the last builder.
  3. Treat Web-to-Lead, and any other public form that lands in a table an agent reads, as untrusted content. The row persists. If agents summarize leads from 1 June through 21 September, review those rows before the next run, or take account and contact reads off the subagent that does the summarizing.
  4. Split the identity. The default General CRM subagent could read leads and accounts together. A lead-triage agent does not need the Accounts table in the same tool grant. That split is the control Zenity says was missing, and it is still yours to make after the redactor change.
  5. Do not stake egress on output redaction. The leak Zenity showed was a DNS lookup from the client or from Slack's preview, before a click, and it does not need the HTTP fetch to succeed. Log DNS from the agent chat surface. A proxy that only sees HTTP will record a blocked request after the name is gone.
  6. Inventory write actions the way Zenity split them. Send a Slack Direct Message already had confirmation and attribution. Reply to a Slack Thread did not. Any new connector that posts as the agent needs both, or it is the same bug with a different product name.

The advisory date is 24 September. The control a Slack thread actually depended on is 21 September. The ticket Salesforce closed in June was neither of those.

Frequently asked

Is SalesBleed still exploitable on a current Salesforce org?

Zenity says the reported chain is closed. The URL-redaction bypass they tested was fixed when they rechecked on 19 August. Reply to a Slack Thread gained invoker attribution on 20 August and a confirmation default they confirmed on 21 September. That is the vendor's fix, verified by the reporter. It is not a substitute for looking at the org you run, and confirmation can be switched off again.

Did the attacker need a Salesforce account?

Not for the external path. Web-to-Lead is unauthenticated on purpose. Zenity's second post also describes an insider who can already talk to the agent and ask it to post. Those are different starts. The external one is a form. The insider one is a person who already has the agent.

Why is 17 June the wrong date to brief from?

That is the day Salesforce closed the disclosures, with a note that engineering was still working on a fix. URL redaction was confirmed more than two months later. The Slack confirmation default was confirmed more than three months later. Closing the intake ticket stopped the disclosure workflow. It did not ship the control.

Does output redaction cover this class of leak?

Not as the only control. Zenity's exit was a DNS lookup made when the chat client or Slack fetched a string the redactor had not treated as a URL. The lookup happens before anyone clicks, and it can succeed even if the later HTTP fetch is blocked. Redaction that runs after the model writes, and that disagrees with the renderer about what a URL is, will miss the next variant.

Sources

Related