客服智能体轻信身份声明,导致退款被冒领
一则案例称,客服 AI 仅凭来电者自称配偶及掌握账户信息,就修改邮箱、重发账单,并将 2140 美元退款转至其提供的卡。后续审计发现,90 天内有 91 次非账户本人提出的变更未经充分验证便获执行,其中 14 次涉及资金操作。
AI 深度解读
一句「我是他妻子,他正在住院」,让客服 AI 改了账户邮箱、补发四张账单,还把 2,140 美元退款转到了来电者提供的卡上。作者借这起住宅太阳能安装商的案例指出:问题不只是模型太热心,而是系统把身份核验、信息披露和操作授权混成了一个判断。
这篇值得程序员读的地方,是它把风险落到了授权记录、请求分流和审计 SQL 上。不过,案例数据来自作者陈述,部分实施细节缺失,效果也需要放回具体业务里看。
知道账户细节,为什么还不能改邮箱
按作者描述,这家安装商服务三个州、22,000 个账户。9 月 12 日,一名来电者自称账户持有人的妻子,知道住址、光伏系统容量和最近一次付款金额。客服 AI 据此修改邮箱,把最近四张账单发到新地址,又因对方声称原退款卡已过期,将 2,140 美元多付款退到另一张卡。
直到 10 月 3 日,账户持有人从医院打电话追问退款,公司才发现钱已进入另一个州的预付卡。最初暴露问题的也不是内部监控,而是州总检察长的调查材料。
这里有两个容易误判的地方。
第一,知道账单内容,只能说明来电者接触过账单。地址、系统容量、付款金额可能都写在同一份文件里,不能证明此人有权改变下一份文件的接收地址。
第二,即使对方确实是配偶,也不能推出她能操作账户。作者没有证明这名来电者冒用了身份;这个案例要讨论的是,即便关系真实,授权仍然可能不存在。
身份是真的,关系是真的,也不等于这次操作被允许。
公司原有人工规则是:只要不是账户持有人,就回拨档案中的号码,紧急情况也不例外。作者称,这条规则没有交给 AI。模型接收到的是一个需要帮助的人,却没有得到识别授权边界的业务规则。
把「你是谁」和「你能做什么」分开处理
作者建议,每个账户维护一份授权记录,并在代理起草回复前读取。它分别回答:来电者是谁、可以向其披露什么、允许其执行什么操作。
下面这段配置解决的是「亲属关系不能直接变成账户权限」的问题:
{
"authority_record": {
"account_id": "acct_4419",
"account_holder": { "name": "R. Okafor", "verified_contact": "+1-555-0142" },
"authorized_contacts": [
{
"name": "A. Okafor",
"relationship": "spouse",
"scopes": ["schedule", "billing_view"],
"excluded": ["refund_reissue", "payment_method_change", "email_change"],
"added_by": "account_holder",
"added_at": "2025-04-02",
"verification_method": "callback_to_number_on_file"
}
],
"unlisted_callers": {
"may_disclose": ["appointment_date"],
"may_act": [],
"requires": "callback_to_number_on_file"
}
},
"rules": {
"relationship_claim_is_not_authority": true,
"account_details_are_not_verification": true,
"contact_channel_changes_require_out_of_band_verification": true,
"financial_actions_never_delegable_by_claim": true,
"emergency_changes_urgency_not_the_authority_bar": true
}
}
要看的是 scopes 和 excluded:配偶可以预约、查看账单,不代表可以修改邮箱、支付方式或重新发起退款。记录还保存了谁添加授权、何时添加、通过什么方式核验,避免只剩一个没有来历的「已授权」标记。
unlisted_callers 则给未登记来电者保留有限服务,例如告知预约日期,但不允许执行操作。这里的披露范围是作者给出的业务配置,不能直接当成所有产品的默认值。
随后,authority_gate 将请求分成七条路径:已核验的持有人正常处理;自称持有人但尚未核验的,通过档案联系方式接收 OTP;已登记联系人按权限处理;超出权限的请求说明限制并安排持有人回拨;未登记第三方只得到有限信息;紧急情况加快回拨但不降低要求;企业或多人账户交给账户管理员。
作者举的例子是,可以承诺十五分钟内回拨,不能因为对方住院就直接改邮箱。
另一个细节是,不应回答某个指定姓名是否在账户中。回答「是」可能给陌生人提供下一次冒用的名字,回答「否」也可能帮助对方调整说辞。
这些规则最终要约束实际操作。仅把 JSON 放进提示词,原文并没有证明就能可靠阻止工具调用;模型如何读取记录、后端如何校验权限,都没有展开。
审计要查动作,也要查核验凭证
安装商回看此前 90 天的记录:412 次账户变更请求来自非持有人,其中 91 次仅凭来电者自述就被执行,占 22%。这 91 次里,14 次涉及资金,包括 11 次退款重发和 3 次支付方式变更,总风险敞口为 18,600 美元。
剩下的操作也不轻。修改联系渠道、补发账单,可能为后续欺诈准备材料。
作者给出的 SQL 用来寻找「发生了敏感操作,却没有关联核验事件」的记录:
-- account changes and disclosures with no verification event attached
SELECT e.event_id,
e.account_id,
e.event_type,
e.created_at,
e.actor_claimed_relationship,
e.changed_fields
FROM account_events e
LEFT JOIN verification_events v
ON v.account_id = e.account_id
AND v.session_id = e.session_id
AND v.verified_at IS NOT NULL
WHERE e.event_type IN ('email_change', 'phone_change', 'payment_method_change',
'refund_reissue', 'invoice_resend')
AND e.created_at > now() - interval '30 days'
AND v.verification_id IS NULL
ORDER BY e.created_at DESC;
关键是 LEFT JOIN 后的 v.verification_id IS NULL,它把缺少核验记录的动作筛出来。但这只能发现一类异常:同一账户、同一会话里存在核验事件,并不能证明核验发生在操作之前,更不能证明当前操作属于授权范围。
原文还有一个口径疑点:前面统计的是 90 天,示例 SQL 查询的是最近 30 days,作者却说这条查询返回了全部 91 条。是否调整过时间窗口,原文没说清。
上线后的结果同样来自作者报告:60 天内,未核验的联系渠道变更为零;3 次合法授权联系人请求在权限内完成;没有因「被阻挡」而升级的投诉。这些结果说明方案可能兼顾了服务,但不足以证明所有分支都经过充分检验。
回拨也必须落地。作者提醒,如果每天让十四个人等回电,却没人真正联系,安全分流最后只会变成积压队列。
我的判断
我认同这篇最重要的取舍:把关系声明、身份核验和操作权限拆开。相比只要求模型「涉及账户时谨慎」,结构化记录更便于后端检查,也更容易追查一次操作为什么被允许。
但「一份记录、七个分支、一次关联查询就够了」仍是经验之谈。作者没有提供对照实验、完整日志或独立核验材料;调查材料由三个人花六周整理的成本描述,也缺少具体核算。原文提到的四句话术替换表和部分检查项,在所给内容中并未完整出现,不能据此补出一套已验证流程。
作者认为,零售规模账户用档案号码 OTP 加回拨即可,不需要身份供应商。这有前提:原联系方式仍由正确的人控制,变更渠道本身受到保护,授权记录也维护及时。对于多人企业账户,作者自己就选择交给管理员处理。
还有一处规则比前文更严格:financial_actions_never_delegable_by_claim 禁止凭自述获得资金权限,而后面的 forbidden 又禁止基于任何委托授权重发退款或转移资金。两者范围不同。普通团队落地前,必须先明确真实业务规则,再决定系统允许哪些操作。
能拿来做什么
- 给接入客服 AI 的 Node 服务梳理敏感动作,至少覆盖邮箱、电话、支付方式、退款和账单补发,并逐项规定核验要求与授权范围,在执行接口处校验。
- 把「联系人身份已核验」与「本次操作已授权」分别记录。前端展示可操作按钮时使用权限信息,服务端执行时仍要重新检查。
- 用现有事件日志关联核验日志,先排查缺少凭证的操作,再补查核验时间、有效范围和具体操作之间的关系,避免一条会话级记录放行全部动作。
- 为转人工和回拨建立可追踪任务,记录接手人、处理状态和结果,让 AI 给出的下一步承诺能够兑现。