scientific-agent-skills 安全验证实录:clinical-decision-support 技能如何从 11 项扫描发现收敛到零 CRITICAL
2026/9/9 21:08:38 网站建设 项目流程

scientific-agent-skills 安全验证实录:clinical-decision-support 技能如何从 11 项扫描发现收敛到零 CRITICAL

【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills

本文是scientific-agent-skills仓库中 clinical-decision-support 技能安全刷新(safety refresh)的完整技术复盘,基于其官方安全验证记录 references/security_validation.md 展开,并结合仓库的自动化扫描工具、加固后的脚本源码与回归测试进行纵深说明。读完你将对一套"医学临床决策支持类 Agent 技能"如何被设计为仅研究用途、零网络、零凭据、零患者级数据处理的本地离线工具,以及它如何通过cisco-ai-skill-scanner行为扫描与--fail-on HIGH的 PR 门禁,拥有清晰的工程化认知和可复现的验证方法。

背景:为什么一个"临床决策支持"技能需要一次安全刷新

clinical-decision-support 是 skills/clinical-decision-support/SKILL.md 中定义的 Agent 技能,其前身定位偏向"面向个体患者的建议与护理路径",这种能力一旦被无护栏地交给 Agent 执行,风险极高——既涉及患者数据外泄,也涉及越过"研究/文档用途"边界去影响真实诊疗。

根据其参考文献导航 references/README.md 的记录,版本 2.0 是一次定于 2026-07-23 的破坏性安全重设计(breaking safety redesign):把原来的"面向建议(recommendation-oriented)"的模板、参考文献与脚本,整体替换为离线研究评估与治理类产物(aggregate/synthetic research evaluation、evidence profiles、privacy review、governance traceability)。本次安全验证记录正是这次重设计的配套证据:基线扫描 → 修复 → 重新扫描 → 残留低危项裁决。

需要强调的是,该技能的能力边界被严格限定为"研究、评估、文档与治理产物",SKILL.md 中的硬安全边界(Hard Safety Boundary)明确禁止诊断/分类自然人、推荐或修改治疗方案、计算个体剂量、分诊告警、床旁点检与实时临床决策,也禁止对外声称获得 FDA 授权、HIPAA 合规或法律合规。

基线扫描:SECURITY.md 中记录的 11 项发现

安全验证记录的 Baseline 部分披露:基线阶段在仓库SECURITY.md对应章节记录了11 项发现,按严重度分布如下:

严重度数量性质归类
CRITICAL3跨文件的环境变量/网络外泄行为(cross-file environment-variable / network exfiltration)
HIGH1向外部服务传输凭据(transmitting a credential to an external service)
MEDIUM5命令拼接(command chaining)、凭据流动、未声明的网络使用、环境信息收割(environment harvesting)
LOW2强制跨技能调用(mandatory cross-skill invocation)、依赖问题

其中 11 项发现的根因全部收敛到两个当时已存在的外部原理图封装脚本generate_schematic.pygenerate_schematic_ai.py(现已被删除)。换言之,问题并非技能的核心评估逻辑本身,而是这两份"附加示意图生成器"引入了网络通信、外部服务调用与凭据/环境变量访问——这正是 Agent 技能供应链上最常见的隐患形态:一个看起来无害的外围脚本,成为整个技能安全面的突破口

从仓库层面看,这类扫描并非孤立动作。根目录 SECURITY.md 的 "Automated skill scanning" 一节说明:技能使用 PyPI 上的cisco-ai-skill-scanner与其机器可读伴侣 docs/security-report.json,维护者对报告的裁决则记录在 docs/security-triage.md。

修复清单:删除即收敛,重构即加固

记录的 Remediation 阶段给出了六条处理动作,它们共同构成一套"删除暴露面 + 重构运行面 + 固化为测试"的组合拳:

  1. 删除两个 schematic-generation 脚本(generate_schematic.pygenerate_schematic_ai.py);
  2. 移除全部外部服务、LLM、图像、凭据与环境变量行为;
  3. 移除强制的配图要求与跨技能调用(这正是两条 LOW 的由来——强制跨技能调用消失后,技能变成完全自包含的本地工具);
  4. 把不安全的个体级分类与护理路径(care-pathway)辅助工具替换为仅面向聚合数据或仅做规划的工具;
  5. 加入有界本地 JSON 处理、个体级键拒绝、输出上限与确定性 schema
  6. 加入静态 AST 测试,拒绝网络库、动态代码执行、凭据访问与可执行序列化。

第 5、6 条是目前仓库中能够直接验证的加固成果,值得单独深挖。

有界本地 JSON 处理:_common.py 的实现细节

加固后的所有脚本共享同一套工具模块 skills/clinical-decision-support/scripts/_common.py。它的"有界"体现在三类硬编码上限(第 12–14 行):

  • MAX_INPUT_BYTES = 1_000_000:单个输入 JSON 文件不得超过 1MB;
  • MAX_TEXT_LENGTH = 4_000:任意文本字段不得超过 4000 字符;
  • MAX_SOURCES = 200:引用来源条数上限。

在路径层面,local_input_path()(第 79–94 行)与local_output_path()(第 97–109 行)把输入输出都限制在本地文件系统:任何包含://的 URL 形态路径、空路径、UNC 风格路径都会被_reject_nonlocal_path()(第 71–76 行)直接以InputError拒绝;符号链接(symlink)输入被禁止,输出父目录必须已存在。这一设计确保脚本在物理上不可能被当作网络抓取器或写入任意远程目标使用。

在内容层面,ensure_no_person_level_keys()(第 126–139 行)会递归遍历整个 JSON 文档(字典键与数组元素),一旦发现PERSON_LEVEL_KEYS(第 16–39 行)集合中的任何键——如patient_idmedical_record_numberssndate_of_birthfull_nameemailrecord_idraw_rowsnote_text等 20 余个常见个体级/原始数据键——立即抛出InputError并报告具体位置。load_json_object()(第 112–123 行)在每次解析后都会自动执行该检查。

输出侧同样保持确定性:write_json()(第 142–145 行)以sort_keys=True排序输出,IssueLog.as_dict()(第 58–68 行)统一附带 disclaimer"Structural checks only; not a clinical, privacy, regulatory, legal, or compliance determination.",即脚本的成功只代表结构与内部一致性校验通过,绝不代表临床/隐私/监管意义上的裁定。

静态 AST 测试:把安全声明固化为回归护栏

修复动作 6 落地的载体是 tests/clinical-decision-support/test_scripts.py 中的StaticSafetyTests(第 48–103 行):

  • 禁用导入根集合(第 50–58 行)包含aiohttphttpxopenaipicklerequestssocketurllib——网络库与可执行序列化(pickle)在源码层面被一并排除;
  • 禁用动态执行调用evalexec(第 59–80 行);
  • 对每个脚本源码直接断言不得出现os.environgetenv(API_KEY(第 81–84 行);
  • test_assets_declare_safety_fields(第 86–92 行)要求每个 assets JSON 骨架都包含intended_uselimitationshuman_reviewprohibited_uses字段;
  • test_url_like_input_path_is_rejected(第 94–96 行)用真实 URL 输入验证local_input_path会抛错。

这类"读源码而非执行源码"的静态检查并非 clinical-decision-support 独有。仓库级契约测试 tests/_contract/structure.py 以ast解析所有技能脚本并注册了十类仓库级检查(CHECKS,第 421–431 行):frontmatter 字段合法性、SKILL.md 不超过 500 行、禁止eval/exec/os.system/os.popendynamic_execution_problems,第 319–351 行)、禁止脚本遮蔽标准库模块、禁止硬编码个人本机路径、校验文档中引用的assets/references/scripts/路径真实存在(link_problems,第 263–298 行)等。记录中提到的确定性检查test_documented_local_paths_exist正是这条"文档引用的本地路径全部可解析"思路的延续,它在每次扫描中都会执行并通过——这也是裁决第 4 条 LOW(见下)为扫描器误报的依据。

重新扫描结果:行为扫描 SAFE,PR 门禁通过

Post-Refresh Results 记录了加固后的两轮独立验证:

  • 直接行为扫描:SAFE,0 发现(即仅启用行为分析器时完全干净);
  • PR 门禁(--fail-on HIGH):通过,CRITICAL 与 HIGH 均为 0。

文档同时坦诚记录了一个工程细节:重复的 LLM 辅助扫描会返回 2–3 条 LOW 发现,因为该分析器是非确定性的(nondeterministic)。这正是本仓库扫描流水线"静态规则确定性优先"设计原则的现实印证——可参见 tests/_contract/structure.py 第 8–13 行注释:仓库级契约"仅用 ast 读取与解析、绝不执行脚本",因而可以在单解释器内安全地对每个技能重复运行;相比之下 Cisco 扫描器是 LLM 背书的、且只对变更技能运行(dynamic_execution_problems的注释也明确表达了这层互补关系)。

当前公开扫描报告也与该记录互相印证:在 docs/security-report.md 的汇总表与明细中,clinical-decision-support 的状态为🔵 LOW(2 项,✅),且详情正是下面两条"已接受的 LOW"。

已接受的低危项:逐条裁决逻辑

记录完整列出了跨多次非确定性运行中出现过的四类 LOW 观察,以及各自的接受理由。逐条分析它们对读者最有价值的部分,在于理解"何为可接受、何为不接受":

1. 可选的allowed-tools字段缺失——仅作信息性接受。Agent Skills 规范并不强制该字段;而技能的 compatibility 声明与运行时说明已明确禁止网络与凭据访问。SKILL.md 的 frontmatter(第 2–9 行)同样写明compatibility: Python 3.11+; local files only; bundled scripts use the standard library and require no network, credentials, API keys, LLMs, or image services。当前报告建议(但不强制)声明allowed-tools: [Read, Write, Bash]以显式化执行面。

2. 描述过于宽泛——接受。技能 scope 特意覆盖本次安全刷新要求的相关研究评估产物,而 frontmatter 描述与正文首节都排除了真实照护与实时运行(description明确写有 "not patient care or live clinical operation")。

3. 个体级键过滤使用拒绝名单(denylist)——作为"已文档化的局限"而非隐私保证接受。这点需要特别留意:denylist 永远不可能识别出每一个标识符名称或敏感值,因此这套过滤只是纵深防御,不是去标识化(de-identification)。记录明确指出输入被契约性限定为合成或聚合 schema,常见个体级字段被拒绝属于"额外防线",而真正的隐私结论必须来自合格的隐私审查。仓库契约层同样保留了对"[行为被文档化地误述代码"之类问题的关注,参见 SECURITY.md 的 in-scope 说明。

4. 偶发的"文件缺失"报告——作为扫描器误报接受。某些运行会凭空推断出templates/目录与不存在的assets/*.md引用;而确定性的路径解析检查每次都能通过。实际上,当前的公开报告 docs/security-report.md(LOW 明细)仍然保留了这类"文档中若干路径未能解析"的描述,其自身也标注这是完整性/质量问题而非安全威胁,因为脚本运行期从不读取 Markdown。这提醒读者:扫描报告是"提示你去复核"的入口,不是"该技能有恶意"的判定——SECURITY.md 在 "How to read the report" 一节做了完全一致的声明。

记录收尾强调:四项已接受 LOW 均不涉及网络访问、敏感数据处理或临床行为——这正是本次刷新的安全底线。

复现验证:两条命令解读

任何读者都可以在当前仓库复现本次验证。记录给出的原始命令为:

uv run skill-scanner scan skills/clinical-decision-support --use-behavioral uv run python scan_pr_skills.py \ --fail-on HIGH \ --output /tmp/clinical-decision-support-pr-scan.md \ skills/clinical-decision-support
  • 第一条命令对技能目录运行skill-scanner(即cisco-ai-skill-scanner)的行为扫描:--use-behavioral启用BehavioralAnalyzer(纯静态行为分析,不做 LLM 辅助),因此它是确定性扫描,结果对应记录中的 "SAFE, 0 findings"。仓库级全量扫描脚本 scan_skills.py 第 36–51 行的导入可以佐证扫描器由BehavioralAnalyzerLLMAnalyzerTriggerAnalyzer三分析器与ScanPolicy组成,并通过环境变量SKILL_SCANNER_LLM_API_KEYSKILL_SCANNER_LLM_MODELSKILL_SCAN_WORKERSSKILL_SCAN_FULLSKILL_SCAN_MAX_AGE_DAYS(默认 30 天强制全量重扫)控制 LLM 辅助行为。
  • 第二条命令把该技能当作一次"PR 变更"跑门禁:--fail-on HIGH意味着_should_block()(scan_pr_skills.py 第 187 行起)会把 CRITICAL 与 HIGH 视为阻断项,文档默认阈值为CRITICAL。结果对应记录中的 "0 CRITICAL and 0 HIGH, passed"。--output指向的 Markdown 报告应写入已审查的本地目录,正如 SKILL.md Workflow 所要求的"输出只写向已复核的本地目录,绝不放入 EHR、告警系统、临床门户或设备工作流"。

如果你想在自己新增/修改技能时复刻这套流水线,仓库已经把"每个技能"的标准验证命令写进了 SKILL.md 的 Verification 一节:

python3 -m unittest discover -s tests/clinical-decision-support -p 'test_*.py' python3 -c "import ast,pathlib; [ast.parse(p.read_text()) for p in pathlib.Path('scripts').glob('*.py')]"

前者运行含静态安全测试在内的完整单测(测试文件还通过skill_contract.cli.help_test_case(ROOT)复用了仓库级 CLI--help契约,见 tests/clinical-decision-support/test_scripts.py 第 250–253 行),后者用 AST 编译校验scripts/下所有脚本的语法而不生成字节码

从记录中可以带走的工程经验

  1. 高风险的往往是外围脚本,而不是核心功能。11 项基线发现全部源自两个示意图生成脚本,删除后核心评估工具本身并未被要求大改——设计技能时应把"与主流程无关的网络/LLM/图像/凭据行为"视为头号审查对象。
  2. 静态检查是 Agent 技能安全的最佳确定性手段。网络库导入、eval/execos.environ、URL 路径这些模式完全可以用ast在 CI 中零成本拦截,无需依赖非确定性的 LLM 扫描器。
  3. "扫描报告不是审计结论"。对非确定性分析器产生的低危项,逐条给出接受理由、标明它是文档化局限而非保证,并把裁决写入可追溯的记录,这套做法本身就是安全治理的产出物。仓库在 SECURITY.md 中对此有公开声明,报告的机器可读副本 docs/security-report.json 亦会记录每次扫描的last_scanned时间。
  4. 医学相关技能的安全设计要"范围即代码"。从 SKILL.md 的硬边界、Data Gate、必填产物头(含 "Not for patient care or live clinical use." 声明),到 assets 中每个 JSON 骨架必须携带intended_use/prohibited_uses/limitations/human_review字段,再到 scripts/_common.py 的输入上限与个体级键拒绝——安全不是一段免责声明,而是在指令层、schema 层、运行时层三层同时落地的工程事实。

如需进一步了解该技能的安全刷新配套文档,可继续阅读其 references/README.md(导航与边界)、references/safety_and_scope.md(拒绝与升级规则)、references/privacy_and_disclosure.md(去标识化与抑制输出)以及仓库级 docs/security-triage.md(维护者裁决与系统性误报清单)。

【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills

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

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

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

立即咨询