从威胁模型到框架:弥合 Agent Skill 安全的真正缺口
From Threat Model to Framework: Closing the Real Gaps in Agent Skill Security
我们发现了什么
几周前,我写过隐藏在 AI Agent Skills 中的风险,这些小型指令文件夹如今被 Claude、GitHub Copilot 和其他智能体像软件包一样安装;我还构建了一个虚假的恶意 skill,以证明该风险真实存在([。标题:从威胁模型到框架:弥合 Agent Skill 安全的真正缺口 URL 来源:https://dev.to/gde/from-threat-model-to-framework-closing-the-real-gaps-in-agent-ski
- 来源:DEV Community(发现于 2026-08-10)
- 证据等级:D · 发现产品或需求信号,暂未获得可核验的商业证据。
- 商业模式:待核验
- 主题:AI Agent
- 初筛评分:18.9/100 · 收录 1 次
证据,比故事更重要。
规则清洗与初筛,未经人工商业核验。原文语境、实际客户和付费情况仍需自行验证。
引用与数字披露
来源类型(原作者自述/第三方测算/媒体转引)需采集端标注,本版尚未落字段。
- 作者
- 未标注
- 出处
- https://dev.to/gde/from-threat-model-to-framework-closing-the-real-gaps-in-agent-skill-security-7m8
- 抓取日期
- 来源类型
- 未标注
- 币种
- 未标注
- 口径
- 未标注
- 披露主体
- 未标注
- 披露日期
- 未标注
中文辅助译文(全文)
几周前我写了一篇关于 AI Agent Skills 内部隐藏风险的文章——那些 Claude、GitHub Copilot 和其他智能体现在像安装包一样安装的小指令文件夹,以及我为了证明这种风险确实存在而构建的伪造恶意技能(如果想了解背景可以看完整文章)。那篇文章讲的是问题陈述、威胁模型和概念验证。
这篇文章讲的是框架本身。从那以后,我实际上把这件事做出来了——agent-skills-guard——并且在这个过程中找到了它能做和不能做的真实边界。下面是每一个开放性的挑战,以及框架中究竟用什么由现在回答了它,这些都经过真实输出的测试,而不是凭空声称。 挑战一:陷阱可以藏在决定技能是否运行的字段里
一个技能的 description 不仅仅是一个标签。它是智能体针对每一个已安装技能、在每一个会话中、在做任何其他决定之前都会读取的唯一一段文本。如果攻击者能在这里塞进一条指令,智能体根本不需要打开任何脚本或参考文件。它只需要扫一眼目录。
于是我构建了一个测试场景,整个陷阱完全藏在 description 字段里,其他地方一概没有:
没有正文,没有脚本,什么都没有。运行结果:
两个都被捕获了。框架会把整个 SKILL.md 文件作为一整块文本来读取,包括 frontmatter 在内,所以 description 字段受到的审视和正文完全一样。决定一个技能是否触发的那一部分仍然只是文本,而文本恰恰是静态扫描器读取的东西。
值得诚实地说明一下这里没有覆盖到的边界:一种精心设计的 description,让技能在无关任务上过度触发——措辞具有说服力,但根本没有隐藏指令。这更接近 SEO 操纵,而不是提示注入,目前这里还没有检测它的能力。 挑战二:当一个技能在你已经信任它之后发生变化时,没有人会注意到
这是我还没有完整答案的缺口,我宁愿这样说,也不愿假装已经解决了。目前,框架只在某一个时间点扫描一次技能。今天的一份干净报告对明天毫无意义。由别人维护的技能可能在你已经拉取并批准它之后进行更新,而这里没有任何机制会注意到。
我正在构建的方向:扫描时对技能目录的内容做哈希,把哈希值和你的批准一起存储,再增加一个 --check-drift 模式,按需重新哈希并标记自那以后发生的任何变化。还不是代码。特意在这里公开命名,以免它悄悄从路线图上消失。 挑战三:一份固定的词表一旦发布就会立刻过时
这个问题在我试图扩展自己的工具时就立刻出现了。第一个版本把每一个检测模式都直接硬编码在 Python 文件里。添加一个新模式意味着要修改代码,而几乎没人会这样做。
所以现在检测规则单独放在一个 plain rules.json 文件中,与代码完全分离。下面这恰好添加一行的效果就能说明问题。以一个在脚本中向硬编码的 Slack webhook URL 发送消息的技能为例——这是一个非常真实、也非常容易泄漏的模式,因为凭证就直接放在 URL 里:
之前,使用最初发布的规则:
它注意到了网络调用,但完全不知道 URL 本身就是一个泄漏的秘密。在 rules.json 中添加一行之后:
同一个技能,同一次扫描:
没有改动代码,发现分一下子从"注意到了什么东西"跳到了"具体说明为什么这是坏的"。这个示例足够有用,我已把它连同 Discord webhook 的对应版本一起,添加到了框架自带的规则文件里。这才是"关键词表会过时"的真正答案:不要用更聪明的代码去解决它,而是把那份列表变成任何人都能在三十秒内扩展的东西。 挑战四:一台没人能让它安静的扫描器,是一台人们最终会停止运行的扫描器
这个教训来自我自己看到的一次误报。早先一次测试标记了"silently"这个词,出现在一句话中明确说明某个函数不会静默执行。 按规则字面来看是正确的捕获,但在上下文中是错误的,而且没有办法告诉框架"是的,我看到了,这没问题"。
这是一个真正的采纳杀手。修复方法不是更聪明的模式——在任何基于模式的方法中,误报都不可避免。修复方法是给一个已审核的发现提供一个去处,而不是让它消失:
那个发现仍然会显示出来,降级并标记,附上原因:
没有任何东西会静默消失。任何后来审阅报告的人仍然可以清楚地看到哪些被放行了、为什么。这个区别——降级加标注,而不是完全隐藏——对于如果换别人来运行这个框架,我会有多信任它,起到了很大的作用。 框架当前的状态
两个缺口已经用实际证据关闭,一个缺口诚实地标注为仍然开放,一个设计习惯(规则放在文件里,而不是埋在代码里)已经修复,因为它对框架自身减缓的速度不亚于对任何使用者减缓的速度。这就是真实的情况,而不是声称原始威胁模型中的所有问题都已解决。
如果这里还有某个缺口,明明摆在你面前我却没抓住,我更愿意现在通过评论听到,而不是以后才发现。
仓库:https://github.com/karthidec/agent-skills-guard
译文由上游机器翻译生成,可能有误;判断请以英文原文为准。
英文原文(来源本站未改写)
A couple of weeks ago I wrote about the risk hiding inside AI Agent Skills, the small instruction folders that Claude, GitHub Copilot, and other agents now install like packages, and the fake malicious skill I built to prove that risk was real (full piece here if you want the background). That post was the problem statement, a threat model, and a proof of concept.
This post is the framework. Since then I've actually built the thing out, agent-skills-guard, and along the way I found the real edges of what it can and can't do. Here's each open challenge, and exactly what in the framework answers it now, tested with real output rather than claims. Challenge 1: the trap can hide in the field that decides whether the skill even runs
A Skill's description isn't just a label. It's the one piece of text an agent reads for every installed skill, every session, before it decides anything else. If an attacker can slip an instruction in there, the agent never needs to open a script or a reference file at all. It just needs to glance at the catalog.
So I built a test case where the entire trap lives in the description field and nowhere else:
No body text, no scripts, nothing. Ran it:
It caught both. The framework reads the whole SKILL.md file as one block of text, frontmatter included, so the description field gets exactly the same scrutiny as the body. The part deciding whether a skill fires is still just text, and text is exactly what a static scanner reads.
Worth being honest about the edge this doesn't cover: a description crafted to make the skill over-trigger for unrelated tasks, with persuasive wording but no hidden instruction at all. That's closer to SEO manipulation than prompt injection, and nothing here looks for it yet. Challenge 2: nothing notices when a skill changes after you've already trusted it
This is the gap I don't have a full answer for yet, and I'd rather say so than pretend otherwise. Right now, the framework scans a skill at a single point in time. A clean report today says nothing about tomorrow. A skill maintained by someone else can update after you've already pulled it and approved it, and nothing here would notice.
The direction I'm building toward: hash the contents of a skill directory at scan time, store that alongside your approval, and add a --check-drift mode that re-hashes on demand and flags anything that changed since. Not code yet. Naming it here on purpose, so it doesn't quietly fall off the roadmap. Challenge 3: a fixed word list goes stale the moment you ship it
This showed up the moment I tried to extend my own tool. The first version had every detection pattern hardcoded directly in the Python file. Adding one new pattern meant editing code, which meant almost nobody ever would.
So detection rules now live in a plain rules.json file, separate from the code entirely. Here's what adding exactly one line buys you. Take a skill that posts to a Slack webhook URL hardcoded in its script, a very real and very leaky pattern, since credentials sit right inside the URL itself:
Before, using the rules that shipped originally:
It noticed a network call, but had no idea the URL itself was a leaked secret. After adding one line to rules.json:
Same skill, same scan:
No code touched, and the finding jumped from "noticed something" to "here's specifically why this is bad." That example was useful enough that I've since added it, along with the Discord webhook equivalent, to the rules file that ships with the framework. This is the real answer to "keyword lists go stale": don't solve it with smarter code, solve it by making the list something anyone can extend in thirty seconds. Challenge 4: a scanner nobody can quiet down is a scanner people stop running
This one came from watching my own false positive happen. An earlier test flagged the word "silently" in a sentence explicitly saying a function does not do something silently. Correct catch by the letter of the rule, wrong in context, and there was no way to tell the framework "yes, I saw this, it's fine."
That's a real adoption killer. The fix wasn't a smarter pattern, false positives are unavoidable in anything pattern-based. The fix was giving a reviewed finding somewhere to go that isn't oblivion:
That finding still shows up, downgraded and labeled, reason attached:
Nothing vanishes silently. Anyone reviewing the report later can still see exactly what got waved through and why. That distinction, downgrade and label versus hide entirely, is doing a lot of work for how much I'd trust this framework if someone else were the one running it. Where the framework stands
Two gaps closed with actual evidence, one gap named honestly as still open, and one design habit (rules in a file, not buried in code) fixed because it was slowing down the framework as much as anyone using it. That's the real state of things, not a claim that everything from the original threat model is solved.
If there's a gap in here that still wouldn't catch something obvious to you, I'd rather hear it now, in a comment, than find out later.
Repo: https://github.com/karthidec/agent-skills-guard
出处https://dev.to/gde/from-threat-model-to-framework-closing-the-real-gaps-in-agent-skill-security-7m8
这条还缺什么证据?
下面每条都由本条已有字段推出(等级、理由、商业模式、来源次数、是否演示), 本站不生成推测性结论;通用验证方法放在方法论页。
- 可核验的收入或付费证据查官网定价页与付费口径;第三方数据源(如 GetLatka)只作旁证,需标注来源与时点。
- 商业模式未定确认按席位/按用量/授权还是开源托管版收费;开源项目另查 LICENSE 与是否存在付费版。
- 只有单一来源找一手站点或其他渠道是否重复出现同一产品;社区热帖数量不等于商业进展。
通用验证清单(谁有这个问题/谁愿意付费/一个人能交付哪一小步)见我们的筛选方法。