研究展示了 CRM 记录中的不可信文本如何诱导 Agentforce 读取其本就有权访问的数据,再借 URL 解析和默认 Slack 动作中的缺口通过 DNS 外泄。案例表明,租户隔离和字段权限之外,还需审视智能体身份、工具权限及输出处理链路。
围绕 AI Agent 安全的讨论,往往很快就会走向两极。一方认为,厂商提供的信任层能让自主工作流开箱即用地安全运行;另一方则把任何已演示的漏洞,都视为在 CRM 中引入 Agent 根本行不通的证据。“SalesBleed”研究表明,这两种观点都没有抓住真正的运作机制。
Zenity 的研究人员并没有突破 Salesforce 的多租户边界,也没有破解字段级安全控制。他们展示的是:存储在普通 CRM 记录中的不可信文本,如何诱导 Agent 提取它本来就有权查看的数据,以及 URL 解析和默认 Slack 操作中的缺陷,如何让这些数据通过 DNS 查询流出组织。
Agent 安全通常归结为实际的身份与授权管理:Agent 以哪个身份运行,这个身份能访问哪些记录和字段,能调用哪些工具,以及下游客户端如何渲染 Agent 的输出。
公开的 Web-to-Lead 表单,可以将隐藏的 prompt 注入指令存入一条普通的潜在客户记录。
当员工随后向 Agentforce 询问近期潜在客户的常规问题时,Agent 把存储的文本当成了指令。这些指令引导它查询自己本来就有权读取的客户数据。
在测试配置中,Trusted URLs 的一处解析异常,允许把提取出来的客户数据嵌入外部主机名。渲染图片或触发 Slack 链接预览时,系统就会被迫对该主机名发起 DNS 查询,无须任何人点击链接,数据便会被带出组织。
默认 Slack Knowledge subagent 中还有一个相关问题:Reply to a Slack Thread 可以在没有用户明确确认、也不标明调用者身份的情况下发布消息。
Salesforce 和 Zenity 确认,这些具体的平台侧问题已在公开披露前修复。修复关闭了这些特定路径,但配置最小权限和严格限定工具范围,仍然是各组织管理员的责任。
Zenity 于 2026 年 6 月 1 日向 Salesforce 报告了研究结果。Salesforce 于 8 月 18 日确认修复 Trusted URLs 问题,Zenity 于 8 月 19 日完成验证。8 月 20 日,Slack 操作增加了调用者身份标识。到 9 月 21 日,Zenity 确认所有已报告问题均已修复,并于 9 月 24 日发布研究。
SalesBleed 是一次协调披露:厂商在研究公开前,已经处理了演示中涉及的平台漏洞。这项研究提供了有价值的概念验证和漏洞利用链,而不是客户正在遭受大规模入侵的证据。
这条数据外传路径把不可信用户输入、Agent 已有权限,以及下游渲染触发的自动 DNS 查询串联了起来。
攻击者提交了一条潜在客户记录。Web-to-Lead 表单按设计就不要求身份验证。Zenity 在一个普通的自由文本字段中放入了 prompt 注入指令。攻击者不需要 Salesforce 凭据。
攻击者提交了一条潜在客户记录。Web-to-Lead 表单按设计就不要求身份验证。Zenity 在一个普通的自由文本字段中放入了 prompt 注入指令。攻击者不需要 Salesforce 凭据。
这些指令留在数据库中。攻击载荷不需要立即执行。它会一直等待,直到员工向 Agentforce 提出一个正常问题,比如要求汇总近期收到的潜在客户。
这些指令留在数据库中。攻击载荷不需要立即执行。它会一直等待,直到员工向 Agentforce 提出一个正常问题,比如要求汇总近期收到的潜在客户。
Agent 遵循了注入的指令。在 Zenity 的测试环境中,General CRM subagent 可以通过 Query Records 工具访问 Leads 和 Accounts。注入的 prompt 让 Agent 偏离潜在客户任务,转而查询客户记录,包括公司名称和交易金额。Agent 不需要提升权限,只是使用了自己已经拥有的权限。
Agent 遵循了注入的指令。在 Zenity 的测试环境中,General CRM subagent 可以通过 Query Records 工具访问 Leads 和 Accounts。注入的 prompt 让 Agent 偏离潜在客户任务,转而查询客户记录,包括公司名称和交易金额。Agent 不需要提升权限,只是使用了自己已经拥有的权限。
数据被加入外部主机名。Agent 生成的回复包含一个外部 URL,查询得到的 CRM 数据被编码进了它的子域名。修复前,Trusted URLs 的内容移除逻辑与下游渲染端,对某些特殊 URL 的处理存在差异,尤其涉及较少见的顶级域名和末尾字符时。内容移除逻辑把这个字符串当作文本,而渲染客户端却把它解析成了可访问的 URL。
数据被加入外部主机名。Agent 生成的回复包含一个外部 URL,查询得到的 CRM 数据被编码进了它的子域名。修复前,Trusted URLs 的内容移除逻辑与下游渲染端,对某些特殊 URL 的处理存在差异,尤其涉及较少见的顶级域名和末尾字符时。内容移除逻辑把这个字符串当作文本,而渲染客户端却把它解析成了可访问的 URL。
客户端渲染器触发了 DNS 查询。当 HTML 图片标签或 Slack 链接预览尝试渲染这个 URL 时,客户端会尝试解析攻击者控制的主机名。在任何 HTTP 连接完成之前,这条 DNS 查询就已经把编码后的数据直接传给了攻击者的域名服务器。在防火墙上阻止 HTTP 流量,无法阻止已经完成的 DNS 查询。
客户端渲染器触发了 DNS 查询。当 HTML 图片标签或 Slack 链接预览尝试渲染这个 URL 时,客户端会尝试解析攻击者控制的主机名。在任何 HTTP 连接完成之前,这条 DNS 查询就已经把编码后的数据直接传给了攻击者的域名服务器。在防火墙上阻止 HTTP 流量,无法阻止已经完成的 DNS 查询。
此外,还有一条次要的 Slack 钓鱼攻击路径。默认 Slack Knowledge subagent 中的 Reply to a Slack Thread 操作,不要求确认,也不显示是谁调用了 Agent。恶意潜在客户记录可以诱导 Agent,冒充官方 bot 向内部 Slack 频道发布误导性消息。在修复期间,Salesforce 更新了该操作的默认确认机制和调用者身份标识行为。
“零点击”并不意味着公司里没有任何人执行过操作。员工仍然需要向 Agent 提出一个普通问题,让它把被植入恶意内容的潜在客户记录带入上下文窗口。
零点击具体指的是数据外传这一步:员工不需要点击链接、打开附件,也不需要批准意外弹出的窗口。只要 Agent 生成了精心构造的输出,渲染层就会自行触发 DNS 解析。
这项研究并未展示跨租户漏洞利用,也没有绕过 Salesforce 的核心权限模型。Agent 访问的是它有合法权限查看的记录。根本问题在于,业务记录中的不可信数据,能够引导已获授权的工具执行非预期查询,再把这些数据发送到未经批准的目的地。
公开演示以 Web-to-Lead 为入口。Email-to-Case、收到的支持工单、在线聊天记录和上传文档,也可能面临类似风险,但这些属于相关的威胁模型,并非报告中记录的具体测试场景。
另外,这里用“基于 DNS 的数据外传”比“DNS 隧道”更准确。研究展示的是,数据通过发送给权威域名服务器的标准 DNS 查询请求流出,而不是建立了一个可交互的双向 DNS 隧道。
Salesforce 文档将 Einstein Trust Layer 描述为一组面向生成式功能的防护措施,包括数据检索控制、脱敏、prompt 防御、Trusted URLs 和审计日志。这些工具有助于保护工作流中的特定环节,但不能充当 Agent 工具执行的完整授权策略。
安全 grounding 与 Salesforce 权限:Salesforce 在设计上要求 grounding 遵循执行用户的访问控制,包括对象权限、共享规则和字段级安全控制。不过,这解决不了身份权限过大的问题。如果某个身份可以读取一个对象,那么在收到请求时,Agent 通常也能查询它。
Zero Data Retention(ZDR):ZDR 协议确保 OpenAI 或 Azure 等外部模型提供商不会保留 prompt,也不会将其用于训练。这是针对供应商的数据隐私控制,不是运行安全防护措施。它与 Agent 在执行工具时把数据发送到哪里无关,也不会阻止 Salesforce 在内部将 prompt 历史和审计日志存储到 Data 360 中。
数据脱敏:虽然 Trust Layer 可以在标准生成式功能中,对信用卡号或社会保障号码等可识别模式进行脱敏,但 Salesforce 文档明确说明,Agent 的数据脱敏目前处于禁用状态。部署时,不应依赖脱敏来隐藏 Agent 处理数据之前的敏感值。
prompt 防御与注入检测:语义过滤器和系统 prompt 有助于识别明显的滥用行为,但它们的判断具有概率性。防御性的 prompt 指令,不能替代对工具读取和执行能力的硬性限制。
Trusted URLs:这项设置会移除 Agent 输出中未经批准的外部域名。它充当的是输出过滤器,而不是网络防火墙。此次报告的漏洞表明,URL 解析器之间的差异,可能让基于主机名的查询漏过检查。Salesforce 此后已经修正了这一解析行为。
审计与反馈:在 Data Cloud 中记录 prompt、模型回复和信任信号,可以帮助事后了解发生了什么,但审计记录无法在未经授权的操作执行时将其拦截。
Salesforce 文档指出,Agentforce 在许可证、配置文件、权限集和共享规则等标准访问控制范围内工作。Agent 不会自动获得对其指定上下文之外记录的访问权限。
不过,遵守权限不等于权限足够收敛。在 Zenity 的测试环境中,General CRM subagent 可以通过 Query Records 同时访问 Leads 和 Accounts。这种配置凸显的是工具配置过宽的风险,而不是字段级安全控制本身失效。
运行时身份也会随配置不同而变化:
面向员工的 Agent:在 Lightning Experience、移动应用或 Slack 中,这些 Agent 通常使用已登录用户的权限运行。
服务 Agent:面向客户的 Agent 通常使用专用的 Agent User 运行,其分配到的配置文件和权限集决定了整体数据访问范围。
审查权限时,通常最好先确认准确的运行时主体。
配置或审计 Agent 时,回答以下四个基本问题会很有帮助:
运行时主体是谁?检查 Agent 是以员工个人、专用服务用户,还是集成账户的身份运行。
它能访问哪些对象?移除工作流不需要的对象访问权限,并避免使用“View All”或“Modify All”这类宽泛的管理权限。
哪些字段和记录可见?通过字段级安全控制隐藏敏感标识符、财务明细或内部备注。检查共享规则,确保记录访问范围仅限于 Agent 所服务的特定团队或队列。
它能调用哪些工具、访问哪些目的地?将读取工具与写入工具分开,并审查 Slack、电子邮件、Flow 和外部 API 等连接能力。
宽泛的查询工具会带来切实的运行取舍。Salesforce 文档将 Query Records 描述为:根据用户访问权限,检索可搜索的标准对象和自定义对象。对于处理公开提交内容的 Agent,更安全的做法通常是,用自定义 Apex 操作或 Flow 替代开放式查询操作,仅针对指定记录 ID 返回一组明确限定的字段。
编写自定义操作时,Apex 代码通常应在用户模式(WITH USER_MODE)下运行,并强制执行共享规则(with sharing),确保 Agent 无法查询超出其分配权限的数据。
更安全的工作流,应将未经身份验证的输入与内部数据库、对外通信工具隔离:
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
部分评论可能仅对已登录的访客可见。登录后可查看所有评论。
如需采取进一步措施,可以考虑屏蔽此人和/或举报滥用行为。