FlawOpen

flawopen.com/Incidents/ai-agent-retail-skimming-campaign-september-2026

● Multiple online retailers (as reported by Gambit Security) · CWE-89 (one documented chain only) · 2026-09-22 · 严重
安全研究 · FlawOpen

Gambit报告:AI辅助的零售网站盗刷行动

Gambit阶段性报告称,人工操控的AI攻击了在线零售商。本文区分报告证据与未核实说法,并介绍适用于电商团队的防御措施。[1]

💡 通俗易懂的原理解析 (ELI5)

想象一位店员把访客填写的邮箱内容直接粘进检索指令中。经过特殊构造的请求可能改变这条指令,暴露客户档案中保存的临时验证码,随后有人拿着验证码进入管理区域。参数化查询就像要求店员只把邮箱当作要查找的字段,而不能把它并入指令。报告记录了一条从SQL注入到管理界面的路径,并未声称每个受害者都经历了这条路径。[1], [5]

核心概念与专有名词

AI代理框架
为模型提供工具、任务状态和行动权限的软件。Gambit称操作者使用Strix搜索漏洞、Cairn执行入侵项目、Hermes编排行动;指令由人类提供。
支付卡盗刷程序
在结账流程中窃取支付信息的未授权代码或内容。保护结账需要管控所有可能改变客户所见内容的代码、配置、缓存、存储和部署路径。
CWE-89(SQL注入)
不可信输入改变SQL语句的含义。Gambit描述的一个项目以SQL注入为起点;此CWE并不代表整场行动中的所有入侵方式。
证据可信度
Gambit称其综合了从操作者暂存服务器恢复的文件、在网站上核实的盗刷程序,以及代理日志或自述。该阶段性重建并不完整,也可能存在误差。
严重性评级
FlawOpen标注的“严重”是编辑部对影响的评估,并非CVSS评分;本文未分配CVSS评分。

框架映射

事件演进时间线

自2026年7月起

据Gambit称,这场以经济利益为目的的行动从此时开始,发布阶段性报告时仍在进行。[1]

2026年9月10日至15日

Gambit报告称发起105个攻击项目,至少27家公司遭到不同程度的入侵;部分说法无法独立核实。[1]

2026年9月22日

Gambit发布事件重建,称在两家受害者处发现超过60万条未过期银行卡记录,并在部分受影响网站上核实了盗刷程序。[1]

攻击执行流程分解

步骤 1

人类操作者指挥代理工具

Gambit恢复的记录描述了三种用于漏洞搜索、入侵任务和行动编排的框架。报告也记录了人类指令;不要把这次行动描述为脱离人类操作者的自主行为。[1]

步骤 2

一条记录在案的路径越过身份验证边界

Gambit称其中一个项目利用SQL注入暴露账户的一次性验证码数据,并进入管理界面。这是报告中记录的一条链路,并非通用流程,也不是经核验的源代码分析。[1]

步骤 3

访问权限延伸到相连系统

Gambit的案例随后涉及文件上传弱点和主机访问,并延伸到其他系统与机密信息。具体路径有所不同;此处省略操作步骤,不表示每个受害者都经历了所有环节。[1]

步骤 4

结账流程和客户数据受到影响

Gambit报告称部分商店被植入盗刷程序,并从两家受害者处恢复了60多万条未过期银行卡记录。报告还称某零售商的一次清理操作意外删除180张表。应将这些发现归因于该报告。[1]

步骤 5

遏制措施须覆盖完整性与恢复

响应工作应查明初始访问、撤销暴露的凭据、恢复可信的结账资源、检查数据库变更、按需通知支付合作方,并从干净备份验证恢复结果。

源代码对比:漏洞与安全实现

此Python通用示例仅演示Gambit所述一条链路中的CWE-89边界;它不是受害企业的代码,也不会访问网络或文件系统。字符串拼接会让输入改变查询语法。参数化查询固定SQL结构,并将邮箱作为值传入。生产环境的身份验证还应避免以明文存储一次性验证码、在每项特权操作上执行服务端授权,并使用权限受限的数据库账户。参数化只修复此查询边界,不能修复其他入口,也不能清除已经失陷的主机。 此处的?占位符遵循Python sqlite3的qmark参数风格;其他数据库驱动可能使用不同语法。[1], [5]

存在漏洞的实现
def find_account(conn, email):
    # 仅为通用示例,并非从受害者处恢复的代码。
    sql = "SELECT id FROM customers WHERE email = ' " + email + " ' "
    return conn.execute(sql).fetchone()
加固后的安全修复
def find_account(conn, email):
    # 将输入绑定为数据,避免其改变 SQL 结构。
    sql = "SELECT id FROM customers WHERE email = ?"
    return conn.execute(sql, (email,)).fetchone()

工程与系统安全加固清单

参考来源