We discovered that Agentforce agents could be hijacked to send phishing messages in Slack. This issue originated from the default Slack Knowledge subagent template and its built-in Reply to a Slack Thread action, which allowed messages to be sent without user confirmation and without any way for other users to know who really initiated the message.
Combined with the URL-redaction bypass described in our first post, this vulnerability could allow either an internal user or an external attacker to deliver phishing links using the agent’s own identity.
Zenity Labs has disclosed all findings to Salesforce who quickly investigated the issue, added proper attribution, and updated insecure defaults to make Agentforce’s integration with Slack more secure. We appreciate Salesforce’s collaborative approach throughout the process and are happy to help strengthen Agentforce’s security configurations.
How Agentforce works with Slack
Agentforce agents can be published straight into Slack, so employees talk to them where they already work rather than in a separate chat interface.

An Agentforce agent doesn’t include all capabilities by default: it uses subagents, each one bundling the actions for a particular domain. For example, a CRM subagent reads and writes records, whereas a Slack subagent searches conversations and posts messages on Slack.
Several Slack-facing subagents come ready to use with Agentforce, such as Slack Knowledge, can be added with exactly 2 clicks including all of their accompanying atomic actions.

For our context, the actions these subagents hold can be roughly divided into two kinds:
- Read actions such as
Search Slack, which finds channels, threads and messages. - Write actions such as
Send a Slack Direct MessageandReply to a Slack Thread, which create new content.
Two controls that protect Slack actions
Most Slack write actions we examined included two protections: confirmation before sending and attribution in the resulting message, as explained below.
User confirmation
User Confirmation requires the agent to ask before performing an action. This gives a user an opportunity to catch an unexpected message before it reaches other users. If an agent is injected with malicious instructions while reviewing CRM data, a confirmation step could potentially interrupt the agent from being hijacked.

Invoker attribution
Invoker Attribution identifies the user who triggered the action. The agent may send the message, but recipients can see which user’s request caused it to do so. This provides context for evaluating the message, a person to contact if something looks wrong, and prevents rogue employees from abusing an agent’s identity.

The exception: Reply to a Slack Thread
The Send a Slack Direct Message action gave us a clean baseline. In our testing, it did everything right: it asked for confirmation and it named the user who invoked it. Reply to a Slack Thread, however, required neither.

The missing confirmation step meant that once Agentforce decided to invoke Reply to a Slack Thread, the message could be sent without the user approving it.
This is essential for indirect prompt injection, since an employee may ask the agent to review a lead, while instructions inside that lead tell it to post a message in Slack. If the agent follows those instructions, the action will provide no confirmation checkpoint before the message reaches its audience.
The missing attribution also affects the impact: recipients see a reply from the agent, without an accompanying indicator identifying the user whose interaction triggered it. The message carries only the agent’s identity, while obscuring the origin of the request.
How the attacks worked
The attack exploited two missing security controls on the Reply to a Slack Thread Agentforce action (which we explained above), allowing exploitation by two types of attackers.
A malicious insider
The simplest version of the attack needs nothing more than someone who can already chat with the agent and use its Slack actions. This could include disgruntled employees, attackers with access to compromised accounts, and any collaborators which can invoke the Agentforce Slack agent and have access to public Slack channels in the organization.
First, the user writes a phishing message and asks the agent to send it into the right thread.

Then, the agent searches Slack, finds the channel, and uses the Reply to a Slack action on that thread. Everyone in the thread reads this message as being sent from the agent, with nothing in it that points back to the malicious insider who actually sent it. They get to walk away clean, with nothing tracing back this malicious activity back to them.

An external attacker
The second scenario extends the entry point explored in our first SalesBleed post.
Agentforce uses your CRM to support your work, and that information sometimes arrives from external sources. An attacker who knows this could place malicious instructions in data submitted to an organization's CRM (such as in a lead submitted through a Web-to-Lead form, which is used by many companies). This is the same entry point we used in our first SalesBleed post.
An internal user later asks Agentforce for something completely benign, such as to assist with a latest lead.

The agent reads the malicious lead, but now follows the malicious instructions in it to do something very different than the user intended. Using the Reply to a Slack action, it now sends a phishing message to numerous Slack channels, without ever requesting any confirmation from the internal user or showing any attribution on Slack. This enables an external attacker to abuse Agentforce as a vehicle for launching a very unique and convincing type of phishing attack.

In both cases, the URL-redaction bypass we discussed on our first SalesBleed post allowed the phishing links to survive filtering and appear in the agent’s messages.
How the phishing URLs survived redaction
Agentforce has a URL-redaction layer which is meant to remove untrusted URLs from its output. This is an additional control that should have prevented the phishing URL from ever reaching any recipients. As we explained in our first SalesBleed post, we bypassed this layer through gaps in how it recognized URLs.
In short: (a) certain top-level domains and URL-ending characters were handled differently by the redactor and the surface consuming the output; and so (b) a tailor-made untrusted URL could pass through without being recognized by the redaction mechanism, and remain usable.
We later also discovered that URLs could be embedded behind benign-looking link text using markdown, which enabled phishing links to appear even more legitimate to recipients.
For this attack, this meant an attacker-controlled phishing link could survive filtering and appear as a legitimate link in Agentforce agent’s Slack reply.
Impact and implications
Salesforce fixed the reported issues in the Reply to a Slack Thread action and the URL redaction bypass, closing these attack chains. However, hijacking enterprise agents via untrusted external data remains a broader risk, and any agent integrated into trusted workplace tools can significantly expand an attacker's reach.
A Slack thread reply is effective for phishing
A thread reply arrives with context already attached to it. It appears where employees are discussing an account, a project, or an operational issue, and reaches an audience that has a reason to pay attention. A request related to that conversation can seem more plausible than an unsolicited message arriving elsewhere.
The agent’s identity adds another source of credibility. Employees may be accustomed to receiving useful information and workflow updates from it. An attacker-controlled reply can take advantage of that familiarity. And as mentioned, this type of elaborate phishing attack can be triggered by a completely external attacker.
Wider attack surface and blast radius
But there’s also a bigger picture. The external attacker scenario shows us that an injection hijacking the agent through a CRM lead can have impact on Slack because the same agent could reach both surfaces.
This means that any agentic integration with additional platforms; connection to additional data sources; and usage of connectors can increase the attack surface, potential impact of attacks and feature creep.
Even one malicious lead can create persistence
The malicious lead stays in the Leads table like any other record. Each time an agent reviews it, the injected instruction can run again, and each run is another shot at posting into Slack. As we said in Part 1, a table that organizations deliberately leave open to the public can create a durable foothold, and nothing about the lead has to expire on its own.
Disclosure Timeline
- June 1, 2026: Reported the findings directly to Salesforce via email.
- June 2, 2026: Salesforce confirmed the reports and communicated that it was working quickly on fixes.
- June 17, 2026: Salesforce closed the disclosures, noting that the engineering team was actively working on a fix.
- August 19, 2026: Zenity Labs confirmed Salesforce’s fix for the specifically reported Trusted URLs bypass.
- August 20, 2026: Zenity Labs confirmed that the Reply to a Slack Thread action now included correct attribution to the invoking user.
- August 25, 2026: Salesforce updated us that they were still working on requiring user confirmation by default for the Reply to a Slack Thread action.
- September 10, 2026: Salesforce confirmed that the fix requiring user confirmation was expected to be completed by September 21.
- September 21, 2026: All fixes were confirmed and tested.
Salesforce’s fixes ensure that the attack path described in this post is no longer possible by default.
However, we encourage organizations to closely monitor write actions configurations when building AI agents. All it takes for the user confirmation requirement to be disabled is a single click of a button, and once disabled the same attack path can become available again.



