从 CRITICAL 到 SAFE:scientific-agent-skills 中 peer-review Skill 的安全加固与验证实录
【免费下载链接】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
本篇技术指南围绕仓库中 peer-review 技能的安全验证记录,完整还原一次 Agent Skill 安全整改的完整闭环:从安全扫描发现10 项含 CRITICAL 级别的基线问题,到删除外部脚本、重构为有界确定性的本地处理,再到多维度验证全部 PASS 并仅保留 3 项 LOW 残留的全过程。读完本文,你将掌握 Agent Skill 在"网络访问、凭据读取、子进程链、图像生成"等高危能力上的审计要点、加固手段,以及如何用 AST 静态测试、行为扫描与 PR 门禁组合验证一个技能达到可发布的安全状态。
一、安全基线:一次扫描暴露的 CRITICAL 问题
1.1 基线背景
在 2026-07-23(项目本地日期)的安全整改之前,仓库 SECURITY.md 记录 peer-review 技能存在10 项安全发现,其中最高严重级别为CRITICAL。这些发现涉及七大类风险:
- 跨文件环境变量与网络数据外泄(Cross-file environment-variable and network exfiltration)
- 多文件采集/传输链(A multi-file collection/transmission chain)
- 两个示意图脚本中的环境信息采集(Environment harvesting in both schematic scripts)
- 向外部模型服务传输 API Key(API-key transmission to an external model service)
- 向子进程传播完整环境变量(Full environment propagation to a subprocess)
- 反复的高成本模型/图像操作(Repeated costly model/image operations)
- 强制的外部示意图生成与跨技能行为(Mandatory external schematic/cross-skill behavior)
1.2 受影响文件
安全发现集中指向三个对象,整改后现状如下:
scripts/generate_schematic.py—— 已删除scripts/generate_schematic_ai.py—— 已删除- 旧版
SKILL.md—— 已重写为 skills/peer-review/SKILL.md
从当前测试可以印证删除动作的真实性:tests/peer-review/test_scripts.py 中的test_no_bytecode_or_removed_schematic_scripts断言generate_schematic.py与generate_schematic_ai.py均不存在,且技能目录内无任何*.pyc字节码产物。
二、整改策略:以有界确定性本地处理替换外部依赖
2.1 修复动作总览
本次整改的核心理念是:删除一切"不必要的外向能力",用"有界、确定性、纯本地"的实现替换之。具体动作包括:
- 删除两个外部示意图脚本,消除环境采集、API Key 传输、子进程链、网络请求、模型调用、图像生成与强制配图能力;
- 移除凭据访问:不读取
.env、环境变量、API Key,也不再向任何子进程传递环境; - 新增严格 schema:所有 JSON/CSV/Markdown 输入必须通过结构化校验;
- 新增重复键/重复表头检测、尺寸/行数/单元格上限、symlink 拒绝、私有原子输出与禁止隐式覆盖;
- 报告最小化:输出仅包含 ID、计数、规则编码与行号,绝不回显稿件或审稿正文;
- 新增 AST 测试:拒绝网络库、可执行序列化、动态代码执行与环境凭据访问;
- 新增保密门禁:机密性、禁止复用、授权、冲突、胜任力、AI 政策、披露、删除/留存共八类检查。
2.2 修复后的能力边界(SKILL.md 强制安全边界)
当前 SKILL.md 明确声明了技能的安全边界,这些约束与本次安全整改直接对应:
- 不向外部服务发送未发表稿件、补充材料、审稿或编辑文本,除非获得出版商/作者明确授权及期刊许可;
- 不上传机密内容到公开模型、搜索引擎、引用服务、语法工具、查重或图像服务;
- 不复用内容用于训练、基准测试、产品改进或不相关研究;
- 不读取宽泛的环境状态、
.env文件、API Key 或凭据; - 捆绑工具不得调用网络、LLM 或图像 API;
- 不自动调用其他技能或 PDF/图像流水线;
- 不冒充审稿人、编辑、期刊、资助方或作者;
- 不捏造稿件细节、审稿结论、引文、分析、实验、复现结果或编辑结论;
- 不代替编辑或评审组宣布决定。
三、源码级安全护栏:_common.py 的底层实现
安全整改不只是文档承诺,更落实在 skills/peer-review/scripts/_common.py 的共享安全基座中。这是所有 peer-review 本地 CLI 共用的依赖无关(dependency-free)安全辅助模块。
3.1 有界输入限制
模块顶部定义了统一的硬性边界常量(L15-L19):
MAX_INPUT_BYTES = 4 * 1024 * 1024 # 单文件上限 4 MiB MAX_ROWS = 5_000 # CSV 最大数据行数 MAX_CELL_CHARS = 12_000 # 单元格最大字符数 MAX_TEXT_CHARS = 50_000 # 文本字段最大字符数 MAX_LIST_ITEMS = 2_000 # JSON 数组最大元素数这些正是安全验证记录中"输入已限制为 4 MiB、5,000 行 CSV、每单元格 12,000 字符"的来源,测试 test_oversized_json_is_rejected_before_parsing 用MAX_INPUT_BYTES + 1字节的超大文件验证了解析前的拒绝逻辑。
3.2 路径安全:symlink 拒绝与无隐式覆盖
safe_input_path(L39-L59)拒绝 symlink 输入、要求必须是常规文件、限制后缀白名单并在解析前检查 4 MiB 尺寸上限;safe_output_path(L62-L85)则要求输出父目录存在、拒绝 symlink 输出,且默认禁止覆盖已有文件,必须显式传--force。测试 test_symlink_input_is_rejected 验证了 symlink 拒绝行为。
3.3 重复键/重复表头检测
_duplicate_safe_object(L30-L36)通过object_pairs_hook在 JSON 解析时拦截重复键;read_csv_records(L117-L180)检查表头不得为空、必须唯一、必须包含必需列、不得含未知列,并逐行校验单元格长度与 NUL 字节。
3.4 私有原子输出
atomic_write_text(L347-L369)使用tempfile.NamedTemporaryFile在目标目录内写入临时文件,设置0o600私有权限后经os.replace原子替换目标。测试 test_private_output_refuses_implicit_overwrite 同时验证了0o600权限位与--force语义。
3.5 报告最小化的代码体现
issue()辅助函数(L391-L393)只产生{"code": ..., "field": ...}的"无内容"发现对象——这正是"输出 ID 与规则编码而非正文"这一保密设计的实现基础。测试中多处断言验证:json.dumps(report)不含稿件文本、不含"ridiculous"等审稿用词、不含引用标题(如 L211、L224、L286)。
四、AST 静态防线:测试如何锁定安全属性
安全验证记录中"显式 AST 解析(禁用字节码)"的承诺,在 test_scripts.py 的test_scripts_have_no_network_dynamic_execution_or_secret_access中有完整实现。该测试对 scripts 目录下每个 Python 脚本做 AST 遍历,断言:
- 无网络库导入:
aiohttp、httpx、requests、socket、urllib、webbrowser等一律禁止; - 无可执行序列化/动态执行:
dill、marshal、pickle、shelve、subprocess禁止导入,eval/exec/compile/__import__禁止调用; - 无环境凭据访问:
os.environ与os.getenv属性访问被 AST 层拒绝; - 无外部服务痕迹:源码中不得出现
openrouter、.env、api_key等字符串。
同一测试文件还断言技能本身不再涉及OPENROUTER、generate_schematic、scientific-schematics、venue-templates等外部技能耦合(L373-L382),与"不再有跨技能调用"的整改目标一致。
五、验证结果:完整 PASS 记录
整改后的验证矩阵如下,全部通过:
| 验证项 | 结果 |
|---|---|
| Agent Skills 参考校验器(reference validator) | PASS |
无依赖 CLI--help检查 | PASS |
| 合成标准库测试 | 26 passed |
| 显式 AST 解析(禁用字节码) | 8 个脚本解析 |
| 字节码产物 | 0 |
| IDE 静态检查 | 0 |
| 文档内本地路径链接测试 | PASS |
| Markdown 链接检查 | PASS(受控 HTTP 403 视为可达) |
| 直接行为安全扫描 | SAFE,0 项发现 |
PR 门禁(--fail-on HIGH) | PASS(CRITICAL 0 / HIGH 0 / LOW 3) |
其中"26 项通过"与"8 个脚本解析"可从当前仓库印证:测试文件覆盖 intake 校验、报告指南选择、claim–evidence 矩阵、统计可复现性、引文审计、scaffold 与 lint、文件安全与静态检查共七个测试类,而 scripts 目录 恰好包含 8 个.py文件(_common.py、audit_citations.py、audit_statistics_reproducibility.py、generate_review_scaffold.py、lint_review.py、select_reporting_guidelines.py、validate_claim_evidence.py、validate_review_intake.py)。
六、残余 LOW 发现:逐条分析与接受理由
最终 LLM 辅助的 PR 扫描报告了 3 项 LOW 发现,均被判定为可接受的信息性观察,没有任何一项允许数据传输或凭据访问:
- 缺少
allowed-tools声明(信息性):该字段在 Agent Skills 规范下是可选项。技能的兼容性声明与正文已明确将捆绑工具限制为仅用本地标准库处理,无网络、模型、图像、凭据或环境访问。 - description 较宽泛(已接受):作为有边界的能力描述被接受。因为强制的授权与期刊政策门禁发生在读取机密内容之前,且技能正文将全部功能限定于同行评审评估。
- 有界 CSV/JSON 处理(防御性观察,"无需处理"):输入已被限制为 4 MiB、5,000 行 CSV、每单元格 12,000 字符与有限列表大小,且测试已覆盖超限拒绝。
结论:无 CRITICAL 或 HIGH 问题残留,none of the LOW findings 允许数据传输或凭据访问。
七、复现指南:如何自行验证
安全验证记录给出了四条可复现的命令(在仓库根目录执行):
# 1) 运行全部单元测试(禁用字节码写入,覆盖 AST 静态断言与功能测试) PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover \ -s tests/peer-review -p "test_*.py" -v # 2) 用 Agent Skills 参考校验器验证技能结构合规 uv run skills-ref validate skills/peer-review # 3) 行为安全扫描 uv run skill-scanner scan skills/peer-review --use-behavioral # 4) PR 门禁扫描:存在 HIGH 及以上发现时以非零码退出 uv run python scan_pr_skills.py \ --fail-on HIGH \ --output /tmp/peer-review-pr-scan.md \ skills/peer-review7.1 PR 门禁的行为语义
第 4 条命令调用的 scan_pr_skills.py 是仓库的 PR 安全门禁工具:它对传入的技能目录逐个扫描(跳过无SKILL.md的目录),并将结果格式化为可在 PR 上发布的 sticky comment。其--fail-on参数(L206-L211)可取值CRITICAL/HIGH/MEDIUM/LOW/NEVER,_should_block(L187-L195)按严重级别排序表["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO", "SAFE"]判断是否阻断。这就是验证记录中"--fail-on HIGH时 CRITICAL 0 / HIGH 0 / LOW 3 仍通过"的原因——LOW 低于阻断阈值。
7.2 行为扫描中的注意事项
行为扫描依赖 LLM 分析器,需要SKILL_SCANNER_LLM_API_KEY环境变量;来自 fork 的pull_request工作流拿不到仓库 secrets,此时工具会"fail open"并写入一段说明性注释(scan_pr_skills.py),这不代表 diff 存在安全问题。因此对 PR 门禁结果需要结合仓库的 安全扫描分流记录 理解——该文件明确强调:"报告中的一条发现是去复核技能的提示,而不是技能恶意的判定",并记录了若干系统性误报类别(如规则匹配eval/exec子串、把服务认证误报为外泄等)。
八、与仓库级安全体系的衔接
本次 peer-review 整改是仓库整体安全治理的一个样本,可对照以下机制理解其上下文:
- SECURITY.md 定义了范围内外判定:"技能执行其文档化工作的固有能力的范围之外"(如 API Key 用于其服务的身份认证),而"读取凭据并传输到意外目的地"在范围内——这解释了本次整改为何聚焦于删除示意图脚本的凭据读取与网络传输,而非技能本身的评审功能。
- docs/security-triage.md 维护了"已验证并修复"与"系统性误报"两类判定,并提供一个可在全仓库验证
eval/exec/os.system/os.environ等风险调用点的 AST 片段。 - 每周增量扫描机制记录每项技能的上次扫描时间;peer-review 的
security_validation.md明确说明仓库级SECURITY.md未被本次局部整改编辑,其快照会通过正常扫描流程自动更新。
结语
peer-review 技能的安全整改给出了一个可复用的 Agent Skill 加固范式:凡是不服务于核心评审功能的"外向能力"(网络、模型、图像、凭据、跨技能调用)一律删除;凡是必须保留的输入输出一律加有界校验与原子私有处理;凡是安全承诺一律写成 AST 断言与行为扫描可验证的测试。从"10 项发现、最高 CRITICAL"到"0 CRITICAL / 0 HIGH、仅 3 项 LOW 信息性观察",整个过程可复现、可审计、可追溯到具体文件与测试用例,这正是 security_validation.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),仅供参考