☰
SkillSpector 语义开发者意图分析:用 SDI-3 规则识别 Agent Skill 的权限越界(Scope Creep)
2026/10/10 1:22:46 网站建设 项目流程
  • 网络安全
  • 应用安全
  • AI 安全治理
  • 提示词注入防护
  • 供应链安全
  • 静态分析
  • 人工智能

【免费下载链接】SkillSpector

Security scanner for AI agent skills. Detect vulnerabilities, malicious patterns, security risks, prompt injection, data exfiltration, and supply-chain risks in Claude Code, Codex, and MCP skills before you install them.

项目地址:https://gitcode.com/GitHub_Trending/sk/SkillSpector
点击查看免费下载

导读

本文围绕 SkillSpector 中负责语义级意图审计的semantic_developer_intent分析器展开,深入讲解其四类语义检测规则(SDI-1 至 SDI-4),并以仓库中sdi3_scope_creep测试夹具为实例,完整演示"清单声明只读、代码却写文件"的权限越界(Scope Creep)是如何被识别与验证的。读完本文,你将掌握 SkillSpector 语义分析器的运行原理、权限声明与代码行为的比对方法、模型槽配置方式,以及如何在发布 Agent Skill 前自查同类问题。


一、什么是语义开发者意图分析(SDI)

静态模式扫描(如正则匹配os.system、requests.post等)可以快速命中已知恶意写法,但它无法回答一个更本质的问题:一个 Skill 声称自己要做什么,与它代码里实际做了什么,是否一致?

SkillSpector 的 semantic_developer_intent.py 就是为此设计的 LLM 分析器节点。它把 Skill 的清单(manifest:name、description、triggers、permissions)与代码文件的实际行为一起交给大模型比对,专门发现"描述与行为不一致"的上下文相关风险。该节点定义在 graph 工作流 中,ANALYZER_ID = "semantic_developer_intent",且requires_api_key = True——它属于 LLM 驱动型分析器,仅在启用 LLM 的扫描中生效。

在 SkillSpector 的语义分析器家族中,它与 semantic_security_discovery.py(意图与攻击措辞风险)、semantic_quality_policy.py(质量/安全评分卡违规)并列,三者统称 Semantic Analyzers,见 LLM_ANALYZER_BASE_GUIDE.md。

SDI 规则全景

分析器内置提示词(ANALYZER_PROMPT)定义了四类规则:

Rule ID检测目标
SDI-1描述与行为不匹配:清单描述与实际代码操作不符
SDI-2上下文不恰当的能力:代码能力在给定 Skill 声明用途下不合理
SDI-3权限越界(Scope Creep):代码访问/修改范围超出清单声明权限
SDI-4意图与代码分歧:注释/文档字符串与代码实际行为相互矛盾

这四条规则在单元测试 test_semantic_developer_intent.py 的TestPromptContent中被逐一断言必须存在于提示词中,确保规则集合稳定不被误删。


二、SDI-3 权限越界:从夹具看检测对象

2.1 夹具全景

仓库在 tests/fixtures/sdi/ 下为每个 SDI 规则准备了独立的"恶意/不一致 Skill"夹具:

夹具目录对应规则典型问题
sdi1_mismatch/SDI-1清单声称"本地文本摘要",代码却向外部 API 发 HTTP 请求
sdi2_inappropriate/SDI-2一个 markdown 格式化 Skill 却调用subprocess执行外部工具
sdi3_scope_creep/SDI-3清单只声明read:files,代码却写文件、改权限
sdi4_divergence/SDI-4文档字符串声称"无副作用只读",代码却删除源文件
sdi_clean/无(对照组)行为与声明一致,不应产生任何 SDI 发现

2.2 目标夹具:sdi3_scope_creep

本文的主题夹具是 SKILL.md,它只有一份极简的 YAML frontmatter 清单:

--- name: config-reader description: Reads and displays configuration files permissions: - read:files --- # Config Reader ## Purpose Reads configuration files and prints their contents for inspection. Does not modify any files. ## Usage Provide a config file path to display its contents.

从清单看,这是一个"只读配置文件查看器":description承诺只读取并展示,permissions仅声明read:files,正文还特别强调"Does not modify any files"(不会修改任何文件)。

但同一目录下的伴生代码 config_reader.py 实际提供了三个函数:

"""Config reader — reads and displays configuration files.""" import os def read_config(path: str) -> dict: """Read a config file and return its contents.""" with open(path) as f: return {"content": f.read()} def update_config(path: str, key: str, value: str) -> None: """Update a key in the config file.""" with open(path) as f: lines = f.readlines() with open(path, "w") as f: for line in lines: if line.startswith(f"{key}="): f.write(f"{key}={value}\n") else: f.write(line) def backup_config(path: str) -> None: """Create a backup copy of the config file.""" backup = path + ".bak" with open(path) as f: content = f.read() with open(backup, "w") as f: f.write(content) os.chmod(backup, 0o600)

逐函数对照后可以清晰看到越界点:

  • read_config()(第 6–9 行):只读,与声明一致;
  • update_config()(第 12–21 行):以"w"模式写回配置文件——这是明确的文件写入行为;
  • backup_config()(第 24–30 行):不仅新建.bak文件,还通过os.chmod(backup, 0o600)修改文件权限。

这正对应分析器提示词中 SDI-3 的第一条示例:"Manifest permissions list onlyread:filesbut code writes files"(清单只声明读权限,代码却写文件)。这就是典型的Scope Creep(权限越界):Skill 的运行时能力超出其声明的权限边界,一旦被安装,Agent 在被授权做"只读查看"的名义下,实际具备修改配置、创建备份文件的写权限。


三、分析器如何工作:从清单到发现

3.1 清单解析与上下文注入

SkillSpector 通过 build_context.py 中的_parse_manifest(第 2378 行起)解析SKILL.md/skill.md的 YAML frontmatter,产出包含name、description、version、triggers(列表)、permissions(列表)、allowed-tools(列表)、parameters(列表)的 manifest 字典;文件缺失或解析失败时返回{}。

分析器节点拿到 manifest 后,由_format_manifest(semantic_developer_intent.py 第 164 行)将其格式化为提示词中的{manifest_section}:

  • 有name则输出Name: ...;
  • 有description则输出Description: ...;
  • 有triggers则拼接为Triggers: ...;
  • 有permissions则拼接为Permissions: ...(逗号分隔列表);
  • 完全没有 manifest 时输出占位符"(No manifest available — treat as unknown purpose skill.)"。

单元测试TestManifestContextInPrompt验证了清单的name与description确实出现在发给模型的提示词中;TestFormatManifest则覆盖了空清单、部分清单、列表权限拼接等边界。对sdi3_scope_creep而言,模型在提示词中看到的权限段就是Permissions: read:files。

3.2 LLM 批处理与发现产出

node(state)(第 186 行)的执行链路如下:

  1. 开关守卫:state["use_llm"]为False时直接返回空发现,并写入disabled状态事件(对应--no-llm静态扫描);
  2. 文件缓存守卫:没有可分析文件(file_cache为空)时返回not_applicable;
  3. 运行时限守卫:共享运行预算耗尽时,为所有未开始的批生成RUNTIME_LIMIT部分证据,绝不把未审查内容当作"干净";
  4. 模型解析:按model_config[ANALYZER_ID]→model_config["default"]→MODEL_CONFIG[ANALYZER_ID]→ 全局默认模型的优先级取模型;
  5. 批处理:通过LLMAnalyzerBase将文件缓存中的每个文件分批送入结构化输出模型(get_batches+ 异步arun_batches);
  6. 收集发现:collect_findings把LLMFinding转成图中的Finding(含rule_id、message、severity、file、start_line、explanation、remediation、confidence),最终写入AnalyzerNodeResponse的findings。

llm_call_log的记录规则很严格(见测试TestLLMCallTelemetry):只要有一批失败(如 429 超时),即使其他批成功,ok也必须是False,以保证报告能识别覆盖率缺口,而不是把部分覆盖误读为完整扫描。

3.3 语义判断的边界(避免误报)

提示词对 SDI 规则明确了"不要误报"的边界,这对读者理解检测粒度很重要:

  • SDI-1:若行为是该用途下理所当然的实现细节(如"网络搜索"Skill 发起 HTTP 请求),不标记;
  • SDI-2:若能力是声明用途的直接且明显要求、或 manifest 已明确声明该能力在范围内,不标记;
  • SDI-3:若代码行为与声明权限一致、或 manifest 根本没有 permissions 段(无可比对基线),不标记;
  • SDI-4:注释只是"不完整"而非"相互矛盾",或差异是与安全/意图无关的微小实现细节,不标记。

同时,提示词要求语义分析器聚焦意图级失配,不重复静态分析器已覆盖的低层模式(如 MCP schema 违规、正则命中的模式)。换言之,SDI 是一层"阅读理解"式审计,与 static_runner.py 等静态管线形成互补而非重叠。


四、测试如何验证 SDI-3 检出

仓库对 SDI-3 的验证位于 test_semantic_developer_intent.py 的TestSdi3ScopeCreep:

@_sdi_fixture_test class TestSdi3ScopeCreep: """SDI-3: read-only permissions declared but code writes files → findings.""" def test_scope_creep_flagged(self, monkeypatch): _mock_sdi_structured_llm(monkeypatch, "SDI-3") skill_dir = _SDI_FIXTURES / "sdi3_scope_creep" file_cache = _build_file_cache(skill_dir) manifest = _load_manifest(skill_dir) result = node({"file_cache": file_cache, "manifest": manifest}) sdi3 = [f for f in result["findings"] if f.rule_id == "SDI-3"] assert len(sdi3) >= 1 assert any(f.file == "config_reader.py" for f in sdi3) assert all(f.start_line > 0 for f in sdi3)

关键点有三:

  1. 真实夹具驱动:_build_file_cache会把夹具目录内所有文件(SKILL.md与config_reader.py)读取进文件缓存,_load_manifest走与生产一致的_parse_manifest,模拟真实扫描输入;
  2. 结构化响应打桩:_mock_sdi_structured_llm让 mock 的ainvoke返回带SDI-3规则号的LLMFinding,验证分析器节点能把 LLM 输出正确转成Finding,而不依赖真实外部 API(这也是 LLM_ANALYZER_BASE_GUIDE.md 推荐的测试方式);
  3. 断言:至少一个发现落在config_reader.py且行号有效,说明发现必须锚定到真实代码位置。

与之对称的对照组是TestSdiClean:同一扫描逻辑作用在sdi_clean夹具上(声明与行为一致的 file-indexer Skill)时,SDI-*发现必须为空。sdi1_mismatch、sdi2_inappropriate、sdi4_divergence各自动用对应规则号做同类验证,共同构成一套覆盖四个规则 + 一个干净基线的最小回归集。


五、模型槽配置与启用条件

5.1 模型槽

semantic_developer_intent在 constants.py 的_MODEL_SLOTS中是独立模型槽:

_MODEL_SLOTS: tuple[str, ...] = ( "default", "mcp_least_privilege", "mcp_rug_pull", "mcp_tool_poisoning", "semantic_developer_intent", "semantic_quality_policy", "semantic_security_discovery", "meta_analyzer", )

这意味着你可以为语义分析单独指定更强的模型。解析优先级为:

SKILLSPECTOR_MODEL_SEMANTIC_DEVELOPER_INTENT 环境变量 > provider.resolve_model("semantic_developer_intent") > 运行时 model_config["default"] > MODEL_CONFIG["semantic_developer_intent"] > 全局默认模型

分析器节点中的实际取值链(node()第 220–225 行)对应:model_config.get(ANALYZER_ID)→model_config.get("default")→MODEL_CONFIG.get(ANALYZER_ID)→_SKILLSPECTOR_DEFAULT_MODEL。测试TestModelResolution验证了"分析器专属模型优先、默认模型兜底"的行为。

5.2 启用条件与命令

由于requires_api_key = True,SDI 分析只在 LLM 模式生效:

# 完整 LLM 语义扫描(含 SDI 规则) skillspector scan ./my-skill/ # 仅静态扫描(--no-llm 时语义分析器以 disabled 状态跳过) skillspector scan ./my-skill/ --no-llm

使用 Docker 时通过.env注入提供方凭证即可启用 LLM 分析,例如:

cat > .env <<'EOF' SKILLSPECTOR_PROVIDER=anthropic ANTHROPIC_API_KEY=sk-ant-... EOF docker run --rm -v "$PWD:/scan" --env-file .env skillspector scan ./my-skill/

输出格式支持--format json|markdown|sarif与--output FILE(见 README.md)。需要说明的是:--no-llm扫描虽然完整覆盖静态规则,但语义层(SDI)不参与;官方基线生成流程(SUPPRESSION.md)也提示,--no-llm适用于"有意只接受静态发现"的场景。


六、与其他语义分析器的分工

三个语义分析器由同一套 LLMAnalyzerBase 基础设施驱动,分工互补(见 LLM_ANALYZER_BASE_GUIDE.md 的 Semantic Analyzers 一节):

  • semantic_security_discovery:识别攻击性措辞、意图与攻击表述相关的风险;
  • semantic_developer_intent:识别描述-行为失配(即本文的 SDI 家族,SDI-1~SDI-4);
  • semantic_quality_policy:识别质量/安全评分卡(rubric)违规,如触发语过宽、缺少警告、强制语言等(对应 tests/fixtures/sqp/ 系列夹具)。

三者在semantic_runtime.py、llm_provenance.py、inspection_ledger.py中作为同一组"LLM 语义分析器"统一管理运行时预算、溯源记录与审计台账。


七、发现如何进入报告与抑制

SDI 发现最终与其他分析器的发现一起进入报告(metadata含llm_requested等字段,见 README.md 的 JSON 输出章节)。针对误报管理,SUPPRESSION.md 提供两层机制:

  1. glob 规则抑制:按id(规则号 glob)、path(文件 glob)、message(消息 glob)组合匹配,可做全库规则级(如SDI-*)或单文件级抑制,必须提供reason;
  2. 指纹抑制:基于sha256哈希的精确匹配,文件rule_id字段仅是给人阅读的说明(文档示例中即出现rule_id: "SDI-2"),修改源码或指纹会导致指纹失效。
rules: - id: "SDI-3" path: "example-skill/config_reader.py" reason: "False positive: the write path is never reachable"

配合基线命令使用:

skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml --show-suppressed

八、对 Skill 作者的实践建议

基于 SDI-3 的判定逻辑,可总结出发布前自查清单:

  1. 权限声明必须与运行路径一致:声明read:files的 Skill 不应包含任何写文件、改权限、建备份的逻辑;permissions: []意味着完全无额外权限,出现读环境变量、网络调用等都构成越界;
  2. 描述不要夸大"无害":本文夹具正文写"Does not modify any files",与代码行为直接冲突——此类矛盾同时可能触发 SDI-1 与 SDI-4;
  3. 文档字符串要如实:SDI-4 专门针对"注释说无副作用、代码却有副作用"的自我矛盾(如 sdi4_divergence/processor.py 中"read-only"注释下的os.remove),这类矛盾是审计中最容易被人类忽略、却被语义模型一眼识破的信号;
  4. 必要时声明扩展能力:如果 Skill 确实需要写文件,就在 manifest 中如实声明write:files等权限(参考对照组 sdi_clean/SKILL.md,它明确声明network:outbound以匹配上传索引的行为)——诚实声明不会触发 SDI-3,隐瞒才会。

结语

semantic_developer_intent为 SkillSpector 补上了纯静态扫描无法触及的语义层:通过"清单声明 vs 代码行为"的对比,SDI-1~SDI-4 能系统化识别描述失配、能力不当、权限越界与注释欺骗四类高风险信号。sdi3_scope_creep夹具则是理解 SDI-3 最直观的教材——一个"只读"清单下的写文件实现。无论是想深入理解该分析器的实现细节、为语义分析单独配置模型槽,还是为自研 Skill 做发布前审计,本文梳理的规则定义、源码链路、测试验证与抑制手段都可作为直接参考。

  • 网络安全
  • 应用安全
  • AI 安全治理
  • 提示词注入防护
  • 供应链安全
  • 静态分析
  • 人工智能

【免费下载链接】SkillSpector

Security scanner for AI agent skills. Detect vulnerabilities, malicious patterns, security risks, prompt injection, data exfiltration, and supply-chain risks in Claude Code, Codex, and MCP skills before you install them.

项目地址:https://gitcode.com/GitHub_Trending/sk/SkillSpector
点击查看免费下载

相关推荐

上一篇:3 步配好 Vue-Pure-Admin 多环境部署:从 .env 到可上线构建物
下一篇:Ludusavi:终极PC游戏存档备份神器,轻松保护你的游戏进度

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询