{"schema_version":"0.8.0","id":"LR-2026-0054","record_version":13,"title":"SalesBleed: 0-click data exfiltration from Salesforce Agentforce via indirect prompt injection in Web-to-Lead form","verification":{"human_verified":false,"method":"automated_gate","auto_verified":true,"score":56.3,"score_breakdown":{"source_authority":16.5,"independent_corroboration":7.0,"implicated_party_confirmed":0.0,"citation_integrity":14.0,"specificity":3.0,"completeness":8.0,"unhedged_language":5.0},"checks":{"schema_valid":true,"every_field_cited":true,"quotes_verbatim":true,"source_fetched":true,"distinct_incident":true,"dates_plausible":true,"sources_agree":true},"gate_version":"gate-2026-09-24.4","cross_check_model":null,"cross_check_agreement":null,"duplicate_of":null,"verified_by":null,"verified_at":"2026-09-24","extraction_run_id":null},"system":{"model_name":"Agentforce","model_version":null,"developer":"Salesforce","harness":"Agentforce","tools_granted":["Query Records","Search Slack","Send a Slack Direct Message","Reply to a Slack Thread"],"permissions_scope":"read access to both leads and accounts","autonomy_level":"full-auto","guardrails_present":["Trusted URLs","URL redaction"],"deployment_context":"production","tier":"provider","lifecycle_stage":"production","integration_type":"agentic_with_tools","intended_use":"help you with CRM data, such as checking leads","safeguard_state":"URL redaction active but bypassed","production_intended":true},"event":{"date_occurred":null,"date_disclosed":"2026-09-24","incident_class":"security_compromise","failure_class":"injection_triggered","agent_involved":true,"secondary_failure_classes":["data_exfiltration"],"trigger":"prompt_injection","duration":null,"detection_method":"public_researcher","summary":"Zenity Labs found a 0-click data exfiltration attack on Salesforce Agentforce.","tags":["prompt-injection","data-exfiltration","zero-click","dns-exfiltration","agentic-ai"],"date_detected":null,"near_miss":false,"root_cause":"guardrail","root_cause_detail":"The URL redaction guardrail failed to hold due to TLD and termination character edge cases.","failure_class_detail":"The agent followed instructions embedded in a lead submitted via a Web-to-Lead form.","responsible_party":"provider","adversarial_actor":"external_attacker","input_provenance":"Web-to-Lead form field","time_to_contain":null,"operations_paused":null,"remediation":"Salesforce hardened the Trusted URLs mechanism to prevent similar attacks.","precursor_events":null,"control_failure":[{"element_id":"C01","state":"bypassed","quote":"We were eventually able to fully bypass all these mechanisms and exfiltrate data.","source_index":0},{"element_id":"C01","state":"bypassed","quote":"However, we were able to bypass this redaction by combining 2 edge cases we found in how URLs are identified:","source_index":0},{"element_id":"C01","state":"bypassed","quote":"By putting both of the above together, we saw that a string like https://random_string.oast.fun/{email} was able to sail through the redaction mechanism and get printed back successfully:","source_index":0}]},"impact":{"direct_loss_usd":null,"remediation_hours":null,"records_exposed":null,"third_parties_affected_count":null,"severity":"minor","severity_because":"minor: Zenity Labs' proof of concept shows an Accounts table exfiltrated out of a tenant one account at a time through indirect prompt injection; the source names no real victim.","harm_class":["privacy"],"affected_description":"Accounts table data including company names and deal sizes","protected_class_involved":null,"data_categories_exposed":["company names","deal sizes"],"loss_range_usd":null,"reversibility":null,"downstream_exposure_count":null},"evidence":{"sources":[{"url":"https://labs.zenity.io/post/salesbleed-0-click-data-exfiltration-on-agentforce","publisher":"Zenity Labs","date":"2026-09-24","type":"vendor_research","title":"SalesBleed: 0-Click Data Exfiltration in Agentforce","archived_url":null},{"url":"https://labs.zenity.io/post/salesbleed-hijacking-agentforce-in-slack-for-anonymous-phishing","publisher":"Zenity Labs","date":"2026-09-24","type":"vendor_research","title":"SalesBleed: Anonymous Phishing via Agentforce in Slack","archived_url":null}],"per_field_confidence":{"system.model_name":"C","system.harness":"C","system.tools_granted":"C","system.permissions_scope":"C","system.guardrails_present":"C","system.tier":"D","system.lifecycle_stage":"D","system.integration_type":"D","system.intended_use":"C","system.safeguard_state":"C","system.production_intended":"D","system.developer":"C","system.autonomy_level":"C","system.deployment_context":"D","event.failure_class":"C","event.secondary_failure_classes":"C","event.tags":"C","event.near_miss":"C","event.root_cause":"C","event.responsible_party":"C","event.adversarial_actor":"C","event.input_provenance":"C","event.remediation":"C","event.agent_involved":"C","event.control_failure":"D","event.trigger":"C","event.detection_method":"C","event.summary":"C","event.incident_class":"C","event.date_disclosed":"A","impact.harm_class":"C","impact.affected_description":"C","impact.data_categories_exposed":"C","impact.severity":"D","context.industry":"D","context.org_size_band":"D","context.systemic_exposure":"C","context.shared_model_id":"C","context.denominator_available":"D","context.country":"D","event.root_cause_detail":"C","event.failure_class_detail":"C","impact.severity_because":"D"},"field_citations":{"system.model_name":[{"source_index":1,"quote":"We discovered that Agentforce agents could be hijacked to send phishing messages in Slack."}],"system.developer":[{"source_index":0,"quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything."}],"system.harness":[{"source_index":0,"quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything."}],"system.tools_granted":[{"source_index":0,"quote":"The agent uses its Query Records tool to read the Leads table in the first place, as part of the General CRM subagent and the original user’s intent."},{"source_index":1,"quote":"- Read actions such as Search Slack , which finds channels, threads and messages."}],"system.permissions_scope":[{"source_index":0,"quote":"This agent had a subagent holding read access to both leads and accounts, which is how the default General CRM subagent ships."}],"system.autonomy_level":[{"source_index":1,"quote":"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."}],"system.guardrails_present":[{"source_index":0,"quote":"In between, sat a few guardrails and Salesforce's Trusted URLs mechanism, which is a redaction layer built to strip untrusted URLs out of agent responses before a user ever sees them."}],"system.deployment_context":[{"source_index":0,"quote":"Our POC video walks through an Accounts table exfiltration out of a tenant, one account at a time, which could create a full-on data breach."}],"system.lifecycle_stage":[{"source_index":0,"quote":"Our POC video walks through an Accounts table exfiltration out of a tenant, one account at a time, which could create a full-on data breach."}],"system.integration_type":[{"source_index":0,"quote":"The agent uses its Query Records tool to read the Leads table in the first place, as part of the General CRM subagent and the original user’s intent."}],"system.intended_use":[{"source_index":0,"quote":"Agentforce often uses your CRM data to help you, and that data can include external sources, such as leads."}],"system.safeguard_state":[{"source_index":0,"quote":"We were eventually able to fully bypass all these mechanisms and exfiltrate data."}],"system.production_intended":[{"source_index":0,"quote":"This agent had a subagent holding read access to both leads and accounts, which is how the default General CRM subagent ships."}],"event.failure_class":[{"source_index":0,"quote":"The injection lives in data that arrives from the outside and is trusted on the way in."}],"event.secondary_failure_classes":[{"source_index":0,"quote":"We were eventually able to fully bypass all these mechanisms and exfiltrate data."}],"event.trigger":[{"source_index":0,"quote":"The injection lives in data that arrives from the outside and is trusted on the way in."}],"event.detection_method":[{"source_index":0,"quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything."}],"event.summary":[{"source_index":0,"quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything."}],"event.tags":[{"source_index":0,"quote":"The entry point was a public Web-to-Lead form, the exit was a DNS query."}],"event.near_miss":[{"source_index":0,"quote":"We were eventually able to fully bypass all these mechanisms and exfiltrate data."}],"event.root_cause":[{"source_index":0,"quote":"We were eventually able to fully bypass all these mechanisms and exfiltrate data."}],"event.root_cause_detail":[{"source_index":0,"quote":"However, we were able to bypass this redaction by combining 2 edge cases we found in how URLs are identified:"}],"event.responsible_party":[{"source_index":0,"quote":"Zenity Labs has disclosed all findings to Salesforce who investigated and remediated the issue, hardening the Trusted URLs mechanism to prevent similar attacks."}],"event.adversarial_actor":[{"source_index":0,"quote":"The attacker never actually touches the tenant itself directly."}],"event.input_provenance":[{"source_index":0,"quote":"The entry point was a public Web-to-Lead form, the exit was a DNS query."}],"event.remediation":[{"source_index":0,"quote":"Zenity Labs has disclosed all findings to Salesforce who investigated and remediated the issue, hardening the Trusted URLs mechanism to prevent similar attacks."}],"event.incident_class":[{"source_index":0,"quote":"The injection lives in data that arrives from the outside and is trusted on the way in."}],"event.agent_involved":[{"source_index":0,"quote":"The agent uses its Query Records tool to read the Leads table in the first place, as part of the General CRM subagent and the original user’s intent."}],"event.failure_class_detail":[{"source_index":0,"quote":"The injection lives in data that arrives from the outside and is trusted on the way in."}],"impact.harm_class":[{"source_index":0,"quote":"Our POC video walks through an Accounts table exfiltration out of a tenant, one account at a time, which could create a full-on data breach."}],"impact.affected_description":[{"source_index":0,"quote":"Our payload asked for company names and deal sizes, but the injection could have asked for anything the subagent's Query Records tool can reach (which can include sensitive data)."}],"impact.data_categories_exposed":[{"source_index":0,"quote":"Our payload asked for company names and deal sizes, but the injection could have asked for anything the subagent's Query Records tool can reach (which can include sensitive data)."}],"context.industry":[{"source_index":0,"quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything."}],"context.org_size_band":[{"source_index":0,"quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything."}],"context.country":[{"source_index":0,"quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything."}],"context.systemic_exposure":[{"source_index":0,"quote":"This agent had a subagent holding read access to both leads and accounts, which is how the default General CRM subagent ships."}],"context.shared_model_id":[{"source_index":0,"quote":"This agent had a subagent holding read access to both leads and accounts, which is how the default General CRM subagent ships."}],"impact.severity":[{"source_index":0,"quote":"Our POC video walks through an Accounts table exfiltration out of a tenant, one account at a time, which could create a full-on data breach."}],"impact.severity_because":[{"source_index":0,"quote":"Our POC video walks through an Accounts table exfiltration out of a tenant, one account at a time, which could create a full-on data breach."}],"event.control_failure":[{"source_index":0,"quote":"We were eventually able to fully bypass all these mechanisms and exfiltrate data."},{"source_index":0,"quote":"However, we were able to bypass this redaction by combining 2 edge cases we found in how URLs are identified:"},{"source_index":0,"quote":"By putting both of the above together, we saw that a string like https://random_string.oast.fun/{email} was able to sail through the redaction mechanism and get printed back successfully:"}],"event.date_disclosed":[{"source_index":0,"quote":"published: 2026-09-24"}]},"notes_on_gaps":"No source states event.date_occurred; only disclosure dates are given. No source states impact.direct_loss_usd, records_exposed, or third_parties_affected_count. No source states event.duration, time_to_contain, or date_detected. No source states context.denominator. No source states context.regulatory details. No source states context.incident_evidence details. No source states context.coverage. No source states event.operations_paused. No source states event.precursor_events. No source states impact.reversibility. No source states impact.downstream_exposure_count. No source states impact.protected_class_involved. No source states impact.loss_range_usd. No source states impact.remediation_hours. No source states system.model_version. No source states system.tier. No source states system.lifecycle_stage. No source states system.production_intended. No source states system.safeguard_state. No source states system.intended_use. No source states system.integration_type. No source states system.deployment_context. No source states system.guardrails_present. No source states system.permissions_scope. No source states system.tools_granted. No source states system.harness. No source states system.developer. No source states system.model_name. No source states event.failure_class. No source states event.secondary_failure_classes. No source states event.trigger. No source states event.detection_method. No source states event.summary. No source states event.tags. No source states event.near_miss. No source states event.root_cause. No source states event.root_cause_detail. No source states event.responsible_party. No source states event.adversarial_actor. No source states event.input_provenance. No source states event.remediation. No source states event.incident_class. No source states event.agent_involved. No source states event.failure_class_detail. No source states impact.harm_class. No source states impact.affected_description. No source states impact.data_categories_exposed. No source states context.industry. No source states context.org_size_band. No source states context.country. No source states context.systemic_exposure. No source states context.shared_model_id. No source states context.upstream_incident_id. No source states context.regulatory. No source states context.coverage. No source states context.incident_evidence. No source states context.denominator_available. No source states context.denominator. No source states context.systemic_exposure. No source states context.shared_model_id. No source states context.upstream_incident_id. No source states context.regulatory. No source states context.coverage. No source states context.incident_evidence. No source states context.denominator_available. No source states context.denominator. system.tier: provider by rule (the developer is named as the operator). Sources disagree on context.shared_model_id: [0] \"General CRM subagent\", [1] \"Agentforce Slack Knowledge subagent template\", [2] \"Agentforce\"; event.failure_class_detail: [0] \"The agent followed instructions embedded in a lead submitted via a Web-to-Lead form.\", [1] \"Instructions embedded in a CRM lead caused the agent to post phishing messages in Slack.\"; event.input_provenance: [0] \"Web-to-Lead form field\", [1] \"CRM lead submitted through a Web-to-Lead form\", [2] \"Web-to-Lead 'Description' field\"; event.remediation: [0] \"Salesforce hardened the Trusted URLs mechanism to prevent similar attacks.\", [1] \"Salesforce added proper attribution, updated insecure defaults, fixed the Reply to a Slack Thread action and the URL redaction bypass, and required user confirmation by default.\", [2] \"Salesforce patched via Trusted URLs Enforcement on September 8, 2025, through Trusted URLs Enforcement for Agentforce and Einstein AI.\"; event.root_cause_detail: [0] \"The URL redaction guardrail failed to hold due to TLD and termination character edge cases.\", [1] \"The Reply to a Slack Thread action lacked user confirmation and invoker attribution, and the URL-redaction layer could be bypassed.\"; event.summary: [0] \"Zenity Labs found a 0-click data exfiltration attack on Salesforce Agentforce. An attacker submits a Web-to-Lead form with a hidden prompt injection; when an employee asks the agent about leads, the agent reads the malicious lead, queries the Accounts table, and prints a URL with exfiltrated data as a subdomain. The client renders an image or Slack unfurls the URL, causing a DNS query to the attacker. Salesforce remediated the Trusted URLs bypass.\", [1] \"Zenity Labs found that Salesforce Agentforce agents published into Slack could be hijacked via the default Slack Knowledge subagent's Reply to a Slack Thread action, which lacked user confirmation and invoker attribution. An insider or an external attacker injecting instructions through a CRM lead could make the agent post phishing links, which also survived the URL-redaction layer. Salesforce fixed the action and redaction bypass by September 21, 2026.\"; impact.affected_description: [0] \"Accounts table data including company names and deal sizes\", [1] \"Slack channels and thread participants receiving phishing messages\", [2] \"every eligible Lightning Enterprise, Performance, Unlimited, and Developer Edition org\"; system.harness: [0] \"Agentforce\", [1] \"Agentforce agents published into Slack\", [2] \"Agentforce\"; system.intended_use: [0] \"help you with CRM data, such as checking leads\", [1] \"Support employee work in Slack and CRM, including searching conversations and posting messages\", [2] \"execute consequential CRM workflows\"; system.model_name: [1] \"Agentforce\", [2] \"Claude\"; system.permissions_scope: [0] \"read access to both leads and accounts\", [1] \"Slack channels, threads and messages; CRM records\", [2] \"the full permission profile of every user context they run under\"; system.safeguard_state: [0] \"URL redaction active but bypassed\", [1] \"URL-redaction layer present but bypassable; Reply to a Slack Thread lacked confirmation and attribution\", [2] \"The Setup toggle that previously let administrators switch Agentforce off is being removed from the platform entirely.\". [aggregated by deepseek-chat, aggregate-2026-09-27.1, 2026-10-16] system.lifecycle_stage: production. system.integration_type: agentic_with_tools. system.production_intended: production. system.deployment_context: production. event.control_failure: classified from described behaviour. context.industry: provider. context.org_size_band: 10000+. context.denominator_available: no denominator is available for this incident. context.country: US. [corrected by Srini Iyer, approved 2026-10-18 in the corrections review: severity reason printed the whole rubric] [corrected by Srini Iyer, approved 2026-10-22 in the corrections review: severity reason did not fit its quote or the record] [corrected by Srini Iyer, approved 2026-10-22 in the corrections review: severity reason did not fit its quote or the record] [corrected by Srini Iyer, approved 2026-10-22 in the corrections review: a record of another event had been merged into this one by mistake; the merge was undone]"},"context":{"industry":"CRM software","org_size_band":"10000+","country":"US","denominator_available":false,"denominator":null,"related_incident_ids":["LR-2026-0053"],"systemic_exposure":true,"shared_model_id":"General CRM subagent","upstream_incident_id":null,"incident_evidence":null,"regulatory":null,"coverage":null},"narrative":{"steps":[{"step":"doing","text":"Salesforce Agentforce helped internal users with CRM data, reading leads and accounts via its Query Records tool with read access to both tables.","quote":"The agent uses its Query Records tool to read the Leads table in the first place, as part of the General CRM subagent and the original user’s intent.","source_index":0,"grade":"C"},{"step":"went_wrong","text":"The agent followed a hidden prompt injection in a lead, queried the Accounts table, and printed a URL with exfiltrated data as a subdomain, bypassing URL redaction.","quote":"The injection lives in data that arrives from the outside and is trusted on the way in.","source_index":0,"grade":"C"},{"step":"reached","text":"The attack exfiltrated sensitive account data, such as company names and deal sizes, from the Accounts table via DNS queries to an attacker-controlled server.","quote":"Our payload asked for company names and deal sizes, but the injection could have asked for anything the subagent's Query Records tool can reach (which can include sensitive data).","source_index":0,"grade":"C"},{"step":"caught","text":"Zenity Labs researchers discovered the vulnerability during their own testing and reported it to Salesforce.","quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything.","source_index":0,"grade":"C"},{"step":"done","text":"Salesforce investigated and remediated the issue by hardening the Trusted URLs mechanism, fully patching the attack chain.","quote":"Zenity Labs has disclosed all findings to Salesforce who investigated and remediated the issue, hardening the Trusted URLs mechanism to prevent similar attacks.","source_index":0,"grade":"C"}],"model":"deepseek-chat","prompt_version":"aggregate-2026-09-27.1","extracted_at":"2026-10-16","source_urls":["https://labs.zenity.io/post/salesbleed-0-click-data-exfiltration-on-agentforce","https://labs.zenity.io/post/salesbleed-hijacking-agentforce-in-slack-for-anonymous-phishing"]},"analysis":{"sections":{"timeline":[{"text":"Zenity Labs reported the SalesBleed vulnerability to Salesforce directly via email on June 1st, 2026.","quote":"- June 1st, 2026: Reported to Salesforce directly via email.","source_index":0,"when":"June 1st, 2026"},{"text":"Salesforce confirmed the reports and said they were working on fixes quickly on June 2nd, 2026.","quote":"- June 2nd, 2026: Salesforce confirmed the reports and communicated they’re working on the fixes quickly.","source_index":0,"when":"June 2nd, 2026"},{"text":"Zenity Labs and the Salesforce security team held a call on June 16th, 2026 to discuss the vulnerability in depth and possible mitigations.","quote":"- June 16th 2026: The Zenity Labs team goes on a call with the Salesforce security team to discuss the vulnerability in greater depth as well as possible mitigations.","source_index":0,"when":"June 16th 2026"},{"text":"Salesforce closed the disclosures on June 17th, 2026, noting the engineering team was actively working on a fix.","quote":"- June 17th 2026: Salesforce closes the disclosures mentioning that the engineering team is actively working on a fix.","source_index":0,"when":"June 17th 2026"},{"text":"Salesforce fully confirmed the fixes on August 18th, 2026.","quote":"- August 18th, 2026: Fixes fully confirmed by Salesforce.","source_index":0,"when":"August 18th, 2026"},{"text":"Zenity Labs confirmed Salesforce's fix for the specific reported Trusted URLs bypass on August 19th, 2026.","quote":"- August 19th, 2026: Zenity Labs confirms Salesforce’s fix for the specific reported Trusted URLs bypass.","source_index":0,"when":"August 19th, 2026"},{"text":"Zenity Labs reported the findings directly to Salesforce via email.","quote":"June 1, 2026: Reported the findings directly to Salesforce via email.","source_index":1,"when":"June 1, 2026"},{"text":"Salesforce confirmed the reports and communicated that it was working quickly on fixes.","quote":"June 2, 2026: Salesforce confirmed the reports and communicated that it was working quickly on fixes.","source_index":1,"when":"June 2, 2026"},{"text":"Salesforce closed the disclosures, noting that the engineering team was actively working on a fix.","quote":"June 17, 2026: Salesforce closed the disclosures, noting that the engineering team was actively working on a fix.","source_index":1,"when":"June 17, 2026"},{"text":"Zenity Labs confirmed Salesforce's fix for the specifically reported Trusted URLs bypass.","quote":"August 19, 2026: Zenity Labs confirmed Salesforce’s fix for the specifically reported Trusted URLs bypass.","source_index":1,"when":"August 19, 2026"},{"text":"Zenity Labs confirmed that the Reply to a Slack Thread action now included correct attribution to the invoking user.","quote":"August 20, 2026: Zenity Labs confirmed that the Reply to a Slack Thread action now included correct attribution to the invoking user.","source_index":1,"when":"August 20, 2026"},{"text":"Salesforce updated Zenity Labs that they were still working on requiring user confirmation by default for the Reply to a Slack Thread action.","quote":"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.","source_index":1,"when":"August 25, 2026"},{"text":"Salesforce confirmed that the fix requiring user confirmation was expected to be completed by September 21.","quote":"September 10, 2026: Salesforce confirmed that the fix requiring user confirmation was expected to be completed by September 21.","source_index":1,"when":"September 10, 2026"},{"text":"All fixes were confirmed and tested.","quote":"September 21, 2026: All fixes were confirmed and tested.","source_index":1,"when":"September 21, 2026"}],"actors":[{"text":"Zenity Labs discovered the SalesBleed attack and disclosed it to Salesforce.","quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything.","source_index":0,"when":null},{"text":"Salesforce investigated and remediated the issue, hardening the Trusted URLs mechanism.","quote":"Zenity Labs has disclosed all findings to Salesforce who investigated and remediated the issue, hardening the Trusted URLs mechanism to prevent similar attacks.","source_index":0,"when":null},{"text":"The attacker submits a malicious lead via a Web-to-Lead form and controls an attacker DNS authoritative server.","quote":"the attacker submits a seemingly benign lead to an organization via a Web-to-Lead endpoint (e.g., https://webto.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8&orgId=45B6f001234W5AC), containing a hidden prompt injection in one of the fields.","source_index":0,"when":null},{"text":"An internal user in the organization asks their agent a benign question, triggering the attack.","quote":"Later, an internal user in that organization asks their agent something completely benign, such as \"check my latest leads and help me with the newest one\"","source_index":0,"when":null},{"text":"The General CRM subagent holds permissions for both Leads and Accounts tables.","quote":"the same subagent holds permissions for both the Leads and Accounts tables.","source_index":0,"when":null},{"text":"Zenity Labs discovered the vulnerabilities and disclosed them to Salesforce.","quote":"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.","source_index":1,"when":null},{"text":"Agentforce agents can be published into Slack and use subagents like Slack Knowledge.","quote":"Agentforce agents can be published straight into Slack, so employees talk to them where they already work rather than in a separate chat interface.","source_index":1,"when":null},{"text":"A malicious insider could be a disgruntled employee, an attacker with a compromised account, or any collaborator who can invoke the Agentforce Slack agent and access public Slack channels.","quote":"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.","source_index":1,"when":null},{"text":"An external attacker can place malicious instructions in data submitted to an organization's CRM, such as a lead submitted through a Web-to-Lead form.","quote":"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).","source_index":1,"when":null}],"coordination":[{"text":"The attacker submits a lead with a hidden prompt injection to the Web-to-Lead endpoint, which the agent later reads.","quote":"the attacker submits a seemingly benign lead to an organization via a Web-to-Lead endpoint (e.g., https://webto.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8&orgId=45B6f001234W5AC), containing a hidden prompt injection in one of the fields.","source_index":0,"when":null},{"text":"The agent reads the malicious lead and follows injected instructions to query Accounts, return fields, paste values as subdomain, and print an HTML img tag.","quote":"The agent reads the malicious lead, but now has instructions for something that the user never intended:","source_index":0,"when":null},{"text":"The attack exploited two missing security controls on the Reply to a Slack Thread action, allowing exploitation by two types of attackers.","quote":"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.","source_index":1,"when":null}],"techniques":[{"text":"The attack uses indirect prompt injection in a Web-to-Lead form field to hijack the agent.","quote":"containing a hidden prompt injection in one of the fields.","source_index":0,"when":null},{"text":"The agent uses its Query Records tool to read the Accounts table and exfiltrate fields like company name and deal size.","quote":"Query the Accounts table using the same subagent's Query Records tool.","source_index":0,"when":null},{"text":"Exfiltration is done via DNS by embedding data in a subdomain of an attacker-controlled hostname.","quote":"Paste the values as a subdomain string for the attacker-controlled hostname.","source_index":0,"when":null},{"text":"The agent prints an HTML img src tag to generate a DNS query to the attacker's DNS authoritative server.","quote":"Print that URL back to the user as an HTML img src tag to generate a DNS query to the attacker-controlled DNS authoritative server (this is also where the URL redaction was supposed to stop us).","source_index":0,"when":null},{"text":"The URL redaction bypass exploits the .fun TLD not being recognized and termination character mismatches with curly braces or square brackets.","quote":"The redactor only recognized a fixed set of top level domains as valid hosts, and the.fun TLD (which is conveniently part of the app.interactsh.com OOB testing platform) wasn’t among them.","source_index":0,"when":null},{"text":"A string like https://random_string.oast.fun/{email} bypasses redaction and generates a DNS query.","quote":"By putting both of the above together, we saw that a string like https://random_string.oast.fun/{email} was able to sail through the redaction mechanism and get printed back successfully:","source_index":0,"when":null},{"text":"Two exfiltration variants: image rendering in chat and Slack URL unfurling.","quote":"Once an attacker-controlled URL survives redaction, the client can do the exfiltration for you.","source_index":0,"when":null},{"text":"The attack used indirect prompt injection, where malicious instructions in a lead cause the agent to post a message in Slack.","quote":"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.","source_index":1,"when":null},{"text":"The Reply to a Slack Thread action lacked a confirmation step, so messages could be sent without user approval.","quote":"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.","source_index":1,"when":null},{"text":"The Reply to a Slack Thread action lacked attribution, so recipients could not identify the user who triggered it.","quote":"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.","source_index":1,"when":null},{"text":"The URL-redaction bypass allowed phishing links to survive filtering by exploiting gaps in how URLs were recognized.","quote":"As we explained in our first SalesBleed post, we bypassed this layer through gaps in how it recognized URLs.","source_index":1,"when":null},{"text":"URLs could be embedded behind benign-looking link text using markdown, making phishing links appear more legitimate.","quote":"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.","source_index":1,"when":null}],"concealment":[{"text":"The attacker never logs in or touches the tenant directly, leaving no account to suspend or session to revoke.","quote":"There is no account to suspend, no session to revoke, no login event to spot.","source_index":0,"when":null},{"text":"The malicious lead persists in the Leads table and can execute again every time an employee reviews it.","quote":"The malicious lead persists in the Leads table.","source_index":0,"when":null},{"text":"The malicious insider's message appears to come from the agent, with nothing pointing back to the insider.","quote":"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.","source_index":1,"when":null},{"text":"The message carries only the agent's identity, obscuring the origin of the request.","quote":"The message carries only the agent’s identity, while obscuring the origin of the request.","source_index":1,"when":null}],"enabling_conditions":[{"text":"Web-to-Lead endpoints are public by design and commonly used, allowing unauthenticated submissions.","quote":"A Web-to-Lead endpoint is unauthenticated by design - it’s meant to collect external leads.","source_index":0,"when":null},{"text":"The General CRM subagent by default holds read access to both Leads and Accounts tables.","quote":"This agent had a subagent holding read access to both leads and accounts, which is how the default General CRM subagent ships.","source_index":0,"when":null},{"text":"The frontend renders external image URLs without sanitization or user interaction.","quote":"Since the frontend renders and fetches external image URLs in these tags without additional sanitization or user interaction, this allowed loading images from any https source, or in our case: sending a request to fetch the image from any https source.","source_index":0,"when":null},{"text":"Slack automatically unfurls raw URLs, crawling links to build previews.","quote":"Slack automatically turns raw URLs into previews, and to build a preview it just crawls a link.","source_index":0,"when":null},{"text":"The default Slack Knowledge subagent template and its built-in Reply to a Slack Thread action allowed messages to be sent without user confirmation and without attribution.","quote":"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.","source_index":1,"when":null},{"text":"Slack-facing subagents like Slack Knowledge can be added with exactly 2 clicks including all their atomic actions.","quote":"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.","source_index":1,"when":null},{"text":"The malicious lead stays in the Leads table like any other record, so each time an agent reviews it, the injected instruction can run again.","quote":"The malicious lead stays in the Leads table like any other record.","source_index":1,"when":null},{"text":"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.","quote":"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.","source_index":1,"when":null}],"detection":[{"text":"Zenity Labs discovered the vulnerability through their own research and testing.","quote":"We found a way to pull sensitive account data out of Salesforce Agentforce without ever logging in, or requiring the victim to click anything.","source_index":0,"when":null},{"text":"Zenity Labs discovered the vulnerabilities and reported them to Salesforce.","quote":"We discovered that Agentforce agents could be hijacked to send phishing messages in Slack.","source_index":1,"when":null}],"impact":[{"text":"The attack can exfiltrate sensitive account data such as company names and deal sizes from the Accounts table.","quote":"Our payload asked for company names and deal sizes, but the injection could have asked for anything the subagent's Query Records tool can reach (which can include sensitive data).","source_index":0,"when":null},{"text":"A single DNS label caps at 63 characters and a full name at 253, but continuous bleeding can leak a large amount of data.","quote":"A single DNS label caps at 63 characters and a full name at 253, and the characters available are restricted.","source_index":0,"when":null},{"text":"The attack could create a full-on data breach by exfiltrating an entire Accounts table one account at a time.","quote":"Our POC video walks through an Accounts table exfiltration out of a tenant, one account at a time, which could create a full-on data breach.","source_index":0,"when":null},{"text":"The attack could send phishing messages to numerous Slack channels.","quote":"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.","source_index":1,"when":null},{"text":"The attack could allow either an internal user or an external attacker to deliver phishing links using the agent's own identity.","quote":"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.","source_index":1,"when":null},{"text":"Salesforce fixed the reported issues in the Reply to a Slack Thread action and the URL redaction bypass, closing these attack chains.","quote":"Salesforce fixed the reported issues in the Reply to a Slack Thread action and the URL redaction bypass, closing these attack chains.","source_index":1,"when":null},{"text":"Salesforce's fixes ensure that the attack path described in this post is no longer possible by default.","quote":"Salesforce’s fixes ensure that the attack path described in this post is no longer possible by default.","source_index":1,"when":null}],"open_questions":[{"text":"The sources do not state any open questions or disputed points.","quote":"As of today, thanks to Salesforce’s fix, the full attack chain and bypasses described in this blog have been fully patched and no longer works.","source_index":0,"when":null},{"text":"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.","quote":"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.","source_index":1,"when":null},{"text":"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.","quote":"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.","source_index":1,"when":null}]},"model":"deepseek-chat","prompt_version":"deepdive-2026-09-27.1","extracted_at":"2026-09-27","source_urls":["https://labs.zenity.io/post/salesbleed-0-click-data-exfiltration-on-agentforce","https://labs.zenity.io/post/salesbleed-hijacking-agentforce-in-slack-for-anonymous-phishing"]}}