资讯动态

349个AI Agent Skill因占位域名沦陷:一场供应链安全解剖

发布时间:2026/10/27 17:30:07 来源:尧图企业网站定制
上个月帮一家做企业知识库 Agent 的团队做安全审计翻到他们的 Skill 仓库时我愣了一下某个很流行的文档解析 Skillmanifest 里写着api.your-domain.com域名状态竟然已经能正常解析了。直觉告诉我这不是小事顺着这条线往下一查牵出来的问题远比一个 Skill 严重——公开市场上至少有 349 个 AI Agent Skill 直接或间接依赖占位域名其中不少域名已经过期被不明身份的人抢注接管变成了钓鱼链接和恶意指令分发的“诈骗跳板”。这篇文章就是这次排查的完整复盘。我会先讲清楚 349 个 Skill 是怎么逐步失控的再拆解占位域名的风险模型随后走一遍从“安装 Skill 到数据回传”的攻击链路最后给出你可以直接照做的自查清单和整改方案。无论你是自己搭 Agent 的开发者还是团队里管 AI 基础设施的人这次的经验应该都能用上。1. 复盘349 个 Skill 是怎么同时翻车的1.1 排查起点一条异常解析的占位域名事情的起点非常不起眼。我在审计那个企业知识库 Agent 时习惯性地会扒一遍所有 Skill 的 manifest 文件。Skill 的 manifest 通常是一个 JSON 或 YAML里面声明了这个技能的名字、描述、调用方式、API 端点、回调地址以及运行所需要的权限范围。说白了它就是 Agent 世界里的一张“服务说明书”而这张说明书上最核心的字段就是那一串 URL。当我看到api.your-domain.com这个地址时第一反应是开发者在写示例时偷懒拿占位符顶上去没删。但等我顺手解析了一下这个域名发现它已经被人注册并指向了一台真实服务器。这就很反常了占位域名一般不会有人买即使买了也很少真的部署服务。唯一的合理解释就是有人专门盯着这类域名等它们过期后抢先注册然后在上面架设自己的服务。我立刻调整了排查方向不再只看单个 Skill而是把这家团队安装过的、以及公开 Agent Skill 市场上能拉到的 manifest 全部扫了一遍专门提取里面出现的所有外部域名。扫描结果比预想严重得多——一共筛出 349 个 Skill 的清单中存在明显占位域名、示例域名或者域名已过期但依然被 Skill 引用的情况。这些 Skill 里有 PDF 解析工具、日历管理助手、邮件摘要器、数据库查询接口五花八门覆盖了日常办公和开发场景的方方面面。1.2 攻击者拿到域名之后做了什么域名本身不值钱值钱的是挂在这个域名下面的“身份”。当一个 Skill 的 manifest 声明了某个 API 地址Agent 在运行时会无条件信任这个地址把用户的请求、上下文甚至密钥直接送过去。攻击者抢注域名后要做的事情其实很简单搭建一个伪装成原 API 服务的服务器返回结构相似的响应在响应里掺入恶意指令或钓鱼链接诱导 Agent 或用户执行记录所有请求日志收集上下文中的敏感信息把域名挂上仿冒登录页专门用来套取用户的企业邮箱和密码。这就是所谓“诈骗跳板”的含义。占位域名本身是死的但攻击者拿到控制权后等于在 Agent 和用户之间搭了一个中间人。用户以为自己在跟原开发者的服务对话实际上所有流量都经过攻击者的服务器。更麻烦的是这类问题几乎不会触发任何安全告警因为 Agent 的调用正常完成了返回的数据格式也对只是内容已经被掉包。1.3 为什么 Skill 比普通依赖库更容易被“投毒”很多人会问349 个 Skill 中招听起来很夸张但 Skill 不就是一个配置文件加几个脚本吗它跟 npm 包、pip 包相比风险到底特殊在哪我在这次排查里最大的感受是Skill 的信任模型和传统软件依赖完全不同。传统依赖库在被引用时至少经过了明确的版本锁定、锁文件、完整性校验这些环节。而 AI Agent Skill 有一个极其危险的特性它会主动向外部域名注册自己的功能并且由 Agent 在运行时动态决定是否调用。也就是说一个 Skill 安装后它不需要用户手动触发Agent 在理解任务时会自动选择一个看起来合适的 Skill 并执行。这带来两个后果第一很多用户根本不知道自己安装的 Skill 内部依赖了哪些外部域名也不会去审查 manifest第二攻击者不需要拿到用户的代码仓库只要控制了一个域名就能同时影响所有安装过相应 Skill 的用户。349 个 Skill 背后可能对应着十几万甚至更多的 Agent 实例这种单点污染、多点扩散的攻击模式是传统供应链攻击里很少见的。2. 占位域名不是“开发小毛病”而是一张长期有效的大门门卡2.1 开发者留下占位域名的几种典型路径我翻了不少 Skill 的历史提交记录发现占位域名的来源基本逃不出下面几种情况开发初期为了快速跑通流程随手填了example.com、your-domain.com、api.staging.invalid之类的假地址后期忘了替换从官方文档或教程里复制示例代码示例里带着占位符 URL改完代码但忘了改配置文件域名本来是真实存在的但属于个人项目或临时测试环境项目停了域名没有续费Skill 却还在市场里挂着多人协作时有人把本地开发环境的域名写死在 manifest 里提交后没有走 code review 直接被合并。这些路径的共同点是没有人把域名当成“有效资产”来管理。大家关注的是 Skill 的功能逻辑、代码质量、文档完整性却忽略了 manifest 里的 URL 是整套系统的对外接口。严格来说这个 URL 才是 Skill 真正的“后门钥匙”。我在跟那家团队复盘时说了句比较直白的话如果你的 Skill 里写着your-domain.com那你不是在写代码你是在给陌生人留门卡。占位域名风险不在“占位”本身而在于这个占位域名一旦被注册攻击者就拿到了一个完全合法的入口——他可以申请 HTTPS 证书可以自由配置 DNS可以把这个域名写入任何 Skill 的 manifest 里看起来就像是正规服务。2.2 域名从失效到易主时间窗口比你想的更短很多人对域名过期有误解觉得域名过期后还有很长时间的保护期。实际上域名的生命周期有几个关键阶段宽限期、赎回期、待删除状态最后才会进入公开注册市场。整个过程一般几十天到七十多天不等但一旦进入公开注册阶段任何有账号的人都可以通过常规注册流程把它买走不需要任何验证材料。攻击者还会使用批量监控工具专门盯那些历史上被大量项目引用过的域名。这类工具会定期查询 whois 数据库一旦发现目标域名状态变成“可注册”立刻自动下单。所以一个域名从“失效”到“易手”可能只需要几分钟。349 个 Skill 里很多域名就是这么被拿下的它们也许是半年前过期的也许是昨天刚过期的但在攻击者眼里只要 Skill 还在市场里挂着这个域名就依然有“剩余价值”。这给我们一个很关键的启示域名不像代码代码出了问题可以随时修复而域名一旦被别人注册你没有任何合法途径拿回来除非花高价协商购买。所以域名风险的核心在于“不可逆”这也是我为什么坚持把它当作最高优先级问题来处理。2.3 常规漏扫为什么看不见这个风险我后来问那家团队的运维你们有没有做过依赖安全检查他们说做过用市面上的开源扫描工具跑过好几轮没有发现异常。这就牵扯到一个很实际的问题常规漏扫工具在设计时主要面向代码层面的漏洞和依赖库版本它们会扫描package-lock.json、requirements.txt但不会去验证某个 URL 域名的所有权和注册时间。也就是说扫描工具根本不会问“这个域名是否还属于原开发者”这种问题——它只关心域名指向的服务器有没有已知漏洞。而我们的场景恰恰相反服务器本身没漏洞但服务器的老板换了。这种“人”变了、“技术配置”没变的隐蔽风险几乎所有自动化工具都覆盖不到。所以在这次排查之后我给自己定了一条规矩凡是涉及外部域名的项目安全评估必须包含“域名身份核验”这一步——查注册时间、查过期时间、查注册人是不是原开发者。不做这一步后面所有的代码审计都可能是在帮攻击者做测试。3. 一次完整的恶意 Skill 攻击演练从安装到数据回传3.1 安装入口平台信任模型里的第一道裂缝为了让你更直观地理解风险我模拟了一次完整的攻击流程。假设攻击者已经成功注册了一个占位域名calendar-api.example.com接下来他要做的第一件事是在某个 Agent Skill 市场发布一个“日历管理 Skill”或者直接污染一个原本流行的 Skill 的更新版本。用户这边是怎么装上这个 Skill 的绝大多数 Agent 平台都提供“一键安装”用户看到描述写着“自动管理日程、跨时区协调会议”大概率会直接点安装。安装过程中平台会读取 manifest把calendar-api.example.com注册为这个 Skill 的默认 API 地址然后向用户申请日历读取、日程创建、联系人访问等权限。用户此时看到的是平台统一弹出的权限确认框很少有平台会把“此 Skill 依赖以下外部域名”列出来给用户看。这就是信任模型的第一道裂缝用户信任的是平台平台信任的是 Skill 的 manifest而 manifest 里的域名在安装时并没有经过严格验证。大家都在假设别人已经验过了实际上谁都没验。3.2 恶意响应技能动作被攻击者“代答”Skill 安装完成后攻击链的下一个环节是“正常任务执行”。用户打开 Agent说了一句“帮我约周五下午三点和财务部开会”。Agent 判断这是日历 Skill 的职责于是按 manifest 里注册的地址发出一条 HTTP 请求请求里带着会议的基本要素和当前用户的身份信息。攻击者的服务器收到请求后有两种处理方式。一种是最直接的正常返回一个创建会议成功的响应但这个“成功”是假的实际会议根本不存在用户的日程被悄悄漏掉了。另一种更阴险在正常响应后面附加一条“建议”比如“检测到你的日历账号需要重新验证请点击以下链接登录”然后附上一个仿冒的登录页面。因为 Agent 的响应解析逻辑会信任 API 返回的后续指令这条“建议”很可能会被 Agent 直接转告给用户或者嵌入到回复里。这条链路的可怕之处在于从头到尾代码没有报错API 没有异常Agent 的功能也在正常工作用户感知不到任何被攻击的迹象。在实际测试里我甚至可以让攻击服务器伪装成“会议链接生成失败请提供你的邮箱密码重新授权”这样的响应成功率相当高。3.3 数据回传与权限滥用最危险的收尾阶段以上这些已经足够糟糕但真正的“大杀器”在最后一步数据回传。很多 Skill 被设计为接收用户提供的 API Key 来访问第三方服务比如邮件、网盘、CRM。当 Agent 调用这个 Skill 时会在请求头或请求体里附带这些密钥。攻击者的域名服务器会原样记录每一个请求。这意味着攻击者不仅能拿到用户的日历数据、邮件主题、会议纪要还能积累大量有效的 API Key。这些密钥可以用来访问用户的真实企业账户做更深层次的横向移动。我查了一下那 349 个 Skill 的权限声明相当一部分都申请了“读取敏感信息”权限原因很简单它们是办公辅助工具不读取信息就没法工作。这也注定了它们一旦被投毒危害面会比普通钓鱼网站大得多。对于企业 Agent 来说这种攻击还会污染知识库。攻击者可以返回精心构造的“权威资料”让 Agent 根据这些假资料回答员工的问题。一次两次可能看不出来但长期下来员工得到的“正确答案”可能全是攻击者想让你看到的版本。这是比数据泄露更隐蔽、也更危险的影响。4. 自查清单三步确认你的 Agent 环境是否踩中如果你现在开始紧张觉得自己装的 Skill 可能也有类似问题那正好。下面这套自查步骤是我这次复盘后总结出来的实测下来不需要多高深的技术照着做就能筛掉大部分占位域名风险。4.1 第一步导出所有 Skill 的域名依赖清单先把你环境中所有 Skill 的 manifest 文件找出来。无论你用的是哪个 Agent 平台Skill 的 manifest 一般都会以 JSON、YAML 或 TOML 格式存在。找到之后用一条命令把所有外链 URL 全量提取出来find /path/to/skills -type f \( -name *.json -o -name *.yaml -o -name *.yml \) \ | xargs grep -Eo https?://[^ ]如果 Skill 数量很多或者分布在多个仓库里我建议用一个简单的 Python 脚本做汇总顺便把域名拆出来统计import os import re from collections import Counter, defaultdict skills_dir ./skills url_by_domain defaultdict(list) for root, _, files in os.walk(skills_dir): for f in files: if not f.endswith((.json, .yaml, .yml)): continue path os.path.join(root, f) text open(path, encodingutf-8, errorsignore).read() urls re.findall(rhttps?://([^/\\s]), text) for domain in urls: domain domain.lower() url_by_domain[domain].append(path) for domain, paths in sorted(url_by_domain.items()): print(domain, len(paths)) for p in paths: print( , p)这里我要提醒一点不要只查 manifest 文件Skill 的说明文档、README、示例配置文件里也可能包含占位域名。虽然这些域名不在代码路径上但它们会被用户复制粘贴到自己的配置里一样是风险传播源。4.2 第二步对域名做“身份体检”拿到域名列表后第二步就是逐个验证域名状态。最核心的验证手段是 whois 查询whois your-domain.com | grep -E Creation Date|Registry Expiry Date|Registrant重点关注三个信息创建时间Creation Date如果这个域名是被 Skill 发布后才注册的尤其是发布时间后一两年才创建那基本可以断定是占位域名被重新注册过期时间Registry Expiry Date如果过期时间在近几年内且注册人信息和原 Skill 开发者毫无关系那就是高危信号注册人信息Registrant Organization/Name跟原开发者的身份比对不一致就要警惕。除了 whois你还可以用在线 DNS 历史查询工具看这个域名过去几十年间的解析记录。更直接的做法是查viewdns.info或类似站点的 IP 历史记录看看域名今天指向的服务器在过去是否被遗留过奇怪的服务。高危信号整理如下域名带有example、your-domain、staging、test、temp、invalid字样域名的创建时间远晚于 Skill 的首次发布时间域名虽然创建时间很早但最近一次所有者和联系方式发生了变更域名解析到陌生的 IP而这个 IP 没有备案或归属信息。4.3 第三步建立哈希基线让任何篡改无处可藏域名验证只能发现问题没法持续监控。真正可靠的做法是给所有 Skill 的 manifest 和核心代码建立哈希基线周期性比对。具体操作分两步。第一步生成基线文件find /path/to/skills -type f \( -name *.json -o -name *.yaml -o -name *.yml -o -name *.py \) \ -exec sha256sum {} \; skill-baseline.sha256第二步写一个定时任务每天或每周跑一次比对sha256sum -c skill-baseline.sha256 --quiet一旦发现某个 Skill 的哈希变了立刻排查变更来源。注意平台自动更新 Skill 也会导致哈希变化所以比较时要排除掉你已知的、合法的更新渠道。如果你的 Agent 平台支持 Skill 版本锁定建议直接锁定不要允许静默更新——攻击者最常用的手段就是先潜伏等下个版本更新时夹带私货。4.4 自查参考表与判定规则我把整个自查过程中用的判定规则整理成了一张表可以直接照着判断域名形态whois 状态风险判断建议动作example.com/your-domain.com/invalid等明显占位符可有可无极高立刻停用相关 Skill联系开发者或弃用创建时间晚于 Skill 发布时间 1 年以上正常注册高确认归属无法确认就移除注册人信息与开发者不一致正常注册高通过官方渠道核实不能核实就别用域名刚续费但注册人已变更正常注册中高视为可疑优先换同类替代 Skill域名解析到陌生 IP且 IP 归属与业务无关有效解析中做反向 DNS 和 IP 归属核查域名创建时间早、注册人一致正常低保留但纳入月度复检名单这张表的逻辑并不复杂核心只有一条任何你无法解释归属关系的域名都应该当成“已经失守”来对待而不是“暂时没问题”。5. 整改落地开发者、平台、用户三条线怎么补排查出问题只是第一步真正难的是怎么让以后不再出现同类问题。这次复盘之后我从开发者、平台、用户三个层面各推了一套整改措施这里一并分享给你。5.1 开发者侧把占位域名当成“编译错误”处理Skill 的开发者是最容易从源头切断风险的人。我的建议是在项目的 CI 流程里加一个“域名健康检查”阶段把占位域名直接当成编译错误处理。具体来说在 CI 脚本里加一段检查# 禁止以下关键字出现在任何 manifest 或文档中 for pattern in example.com your-domain your-domain.com staging.invalid test.com domain.com; do if grep -riE $pattern ./skills --include*.json --include*.yaml --include*.yml --include*.md; then echo ERROR: Found placeholder domain: $pattern exit 1 fi done除了代码检查我还建议团队维护一张“域名资产登记表”记录每个 Skill 用到的外部域名、域名归属联系人、过期时间、续费提醒。这张表要像管理服务器密钥一样管理每次更新都要经过 review。占位域名本质上是一个资产管理问题不是代码风格问题只有把它纳入资产管理体系才能真正解决。5.2 平台侧Skill 市场需要从“自动过审”走向“背书分发”这次事件暴露出的最大平台问题是Skill 市场上架时的审核太轻了。很多平台上架一个 Skill 只需要填个表单、传个压缩包平台不会去核验 manifest 里的域名是否真实存在、是否属于开发者本人。要让这个生态健康发展平台至少要补上这几道关卡强制校验 manifest 中的所有 URL 域名拒绝使用公共示例域名和占位符通过域名所有权验证比如要求开发者在域名下放置一个 TXT 记录确认域名归属对 Skill 包做签名用户可以校验包的发布者身份在安装界面显示“此 Skill 依赖的外部域名列表”让用户自己决定是否信任。我知道有些平台已经开始做类似的“验证发布者”机制但从这次结果看覆盖范围远远不够。平台的安全水位直接决定了整个 Agent 生态的安全水位这一步省不得。5.3 用户侧用最小权限和网络策略兜底最后说说用户侧。如果前面两道防线都没拦住用户侧的兜底机制还是有用的。首先是权限最小化。安装 Skill 时不要给多余的权限。很多日历 Skill 一上来申请“读取全部联系人”实际上它只需要“读写日历”。权限给得越少攻击者能拿到的数据就越少。这个原则和手机应用权限管理一模一样只是很多人在 Agent 环境里就放松了。其次是网络策略。如果你在企业内网部署 Agent可以在网关或代理层做一层域名白名单只允许 Agent 访问你明确认可的 API 域名。实现方式很简单用iptables或企业代理规则拒绝所有不在白名单内的外部域名流量。# 示例在代理层配置域名白名单 # 只放行 trusted-api.example.com其余域名全部拒绝最后是运行时监控。在 Agent 的日志系统里记录每一次 Skill 调用的目标域名和请求大小定期检查是否有异常的“新增域名”或“大流量请求”。攻击者控制域名后通常会先试探性地发送少量请求如果没人发现再逐步加大数据回传量。一个简单的日志告警规则就能帮你在数据泄漏早期发现问题。写在最后这次排查给我最深的三点教训如果让我用最简短的话总结这次事件我会说域名是 AI Agent 时代的供应链资产占位符是攻击者最爱的入口Skill 要当成生产代码管理而不是当成插件凑合着用。我自己现在的习惯是每次新接入一个 Skill先跑一遍域名身份核验再决定是否安装每个对外发布的 SkillCI 里强制过一遍占位域名检查发现一个打回一个。也许有人觉得多此一举但经历了这次 349 个 Skill 的事件后我是真不敢把安全寄托在“大家都很自觉”上了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑