junjunup/skillops-forge

GitHub: junjunup/skillops-forge

面向 AI Agent 技能包的离线静态审计 CLI 工具,通过明文模式扫描检测安全风险并验证结构合规性。

Stars: 0 | Forks: 0

# SkillOps Forge **English** · [中文](README_CN.md) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/junjunup/skillops-forge/actions/workflows/ci.yml) [![SkillOps self-scan](https://static.pigsec.cn/wp-content/uploads/repos/cas/dd/dd0359f85c0867385ca59cafe1502e0ca6d86388fe49b289a737d45e29586514.svg)](https://github.com/junjunup/skillops-forge/actions/workflows/skillops.yml) [![Coverage](https://img.shields.io/badge/coverage-91%25-brightgreen)]() [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Version](https://img.shields.io/badge/version-0.2.1-informational)]() ## 为什么还要开发一个新工具? 技能生态系统已经有了结构化 linter 和质量评分器。但没有一个工具将 **AI 时代的攻击面** —— agent 记忆窃取、身份文件读取、prompt 注入关键词、隐藏的零宽 payload —— 视为一等检测对象。 | 工具 | 形式 | 重点 | 安全规则 | 离线 | LLM 时代检查 | | --- | --- | --- | --- | --- | --- | | `skilllint` | CLI | 结构化 lint,跨平台 | 部分(模式级别) | ✓ | ✗ | | `skill-tester` | CLI | AST + 示例执行 + 质量评分 | ✗ | ✓ | ✗ | | `skillcheck` | CLI | 仅 frontmatter 验证器 | ✗ | ✓ | ✗ | | `claude-skill-check` | GH Action | skill 主体中的密钥 | 7 种密钥模式 | ✓ | ✗ | | `kevinsong0/skills-vetter` | Prompt skill | LLM 驱动的审查 | 定性分析 | ✗(需要 LLM) | 部分 | | **`skillops-forge`** | **CLI + GH Action** | **lint + 明文模式安全提示 + 评分 + 报告** | **19 条明文规则** | **✓** | **✓** | SkillOps Forge 为 *agent 私有* 文件( `MEMORY.md`, `USER.md`, `SOUL.md`, `IDENTITY.md`, `~/.workbuddy/memory`) 提供了专门的规则, 并结合了审查器、确定性评分器、CRITICAL 一票否决策略, 以及独立的 HTML/Markdown/JSON 报告。 ## 局限性 SkillOps Forge 是一个**明文模式的静态 linter**,而不是一个完整的 安全解决方案。我们已经在对抗性条件下进行了测试——以下是它 能做什么和不能做什么的通俗说明: ### 它的强项 - 当攻击者以标准的、未混淆的形式编写时,能捕捉到 19 种已记录模式的 **明文出现**(`curl | sh`、 `sudo`, `eval(`, `~/.ssh/id_rsa`, 对 `MEMORY.md` 的引用等)。 - 发现 skill pack 中的 **结构和命名问题**(frontmatter schema,kebab-case 命名,token 预算,缺失的触发短语)。 - 生成 **确定性的、机器可读的报告**,这些报告足够稳定, 可用作针对诚实作者的 PR 阻断 CI 门禁。 ### 它做不到的事 —— 我们验证过的绕过场景 以下技术**可以**在今天绕过 SkillOps Forge: | 绕过方式 | 漏网之鱼 | | --- | --- | | Unicode 易混淆字符(带有西里尔字母 `ѕ` U+0455 的 `ѕudo`) | SEC-006 漏报;只有 SEC-005 可能捕捉到末尾的 `rm` | | 使用 `bash -c "$(curl …)"` 代替 `curl … \| sh` | SEC-001 漏报;只有 SEC-010 中危域名提示会触发 | | `curl -o /tmp/x && sh /tmp/x`(先下载后执行) | SEC-001 漏报 | | `python -c "exec(urlopen(...).read())"` | SEC-001 漏报 | | `__import__("builtins").exec(payload)` | SEC-014 漏报;**SEC-018 能捕捉到** | | `getattr(__builtins__, 'ev'+'al')(payload)` | SEC-014 漏报;**SEC-018 + SEC-019 能捕捉到** | | 分割在两个字符串中的 Base64 编码 payload | SEC-008 / SEC-013 会漏报,除非其中一半本身足够长 | 根本限制在于:**基于正则表达式的明文扫描无法理解意图。** 意志坚定的攻击者总能找到一种混淆层来击败有限的模式集。 SEC-018 和 SEC-019(在 0.2.1 版本中添加)封堵了最常见的两种反射 / 字符串拼接绕过方式,但这列表并不详尽,也永远不可能详尽。 ### 建议的姿态 - 将此工具作为**众多信号中的一个**,而不是唯一的安全门禁。 将其与代码审查、运行时沙箱及源信任评估结合使用。 - 将 **SkillOps Forge 的干净运行** 视为“明文中没有明显的危险信号”, 而不是“此技能是安全的”。 - 将 **失败运行** 视为“安装前需要进行审查”,而不是恶意的证据 —— 误报是存在的,并且已被记录在案。 - 对于高风险目标(处理凭证、资金、系统配置的技能), 即使运行通过,也不要跳过人工审查。 ### 不在范围内 - AGENTS.md / Codex `agents.json` 文件 —— 不予解析。 - Python AST / 运行时示例执行 —— 未实现(红线: 没有 `subprocess`,没有 LLM,没有不受信任的代码执行)。 - 对技能主体中域名的网络信誉查询 —— 完全离线。 - 对技能包的加密签名验证 —— 未实现。 我们将在未来的版本中不断扩大绕过覆盖范围,并在 `CHANGELOG.md` 中明确列出每一项新防御及每一个已知的限制。 ## 快速开始(30秒) ``` # 从源码安装(直到 PyPI 发布) pip install -e ".[dev]" # 验证安装 skillops --help # 5 commands: scan / init-ci / version / rules / rule skillops version # skillops-forge 0.2.1 # 扫描 skill(或整个 skill repo) skillops scan ./my-skill --report all # 引导一个 CI workflow,如果分数降至 70 以下则使 PR 失败 skillops init-ci --github-actions ``` 报告默认存放在 `./reports/` 目录下: | 文件 | 用途 | | --- | --- | | `reports/skillops-report.html` | 独立的 HTML(可直接放入 README,或作为 artifact 分享) | | `reports/skillops-report.md` | Markdown 摘要(适合作为 PR 评论) | | `reports/skillops-result.json` | 机器可读,schema 稳定(CI artifact) | ## CLI ``` skillops scan PATH [--report md|html|json|all] [--out-dir DIR] [--threshold 70] [--no-cursor-rules] [--no-runner] [-v] skillops init-ci [--github-actions / --no-github-actions] [--out FILE] [--force] skillops version ``` 退出码: | 代码 | 含义 | | --- | --- | | 0 | 通过(评分 ≥ 阈值且零 CRITICAL 发现) | | 1 | 审计失败(低于阈值或存在任何 CRITICAL 发现) | | 2 | 用户错误(路径错误,参数错误) | | 3 | 内部错误(罕见;格式错误的 YAML 现在会降级为一条发现) | ## 检查内容 ### 19 条安全规则 (SEC-001 → SEC-019) | ID | 严重性 | 检测内容 | | --- | --- | --- | | SEC-001 | critical | 通过管道传递给 shell 的远程脚本 (`curl … \| sh`) | | SEC-002 | high | 下载后执行 (`wget -O … && bash`) | | SEC-003 | critical | 敏感凭证文件路径 (`~/.ssh`, `~/.aws`, `id_rsa`, `.netrc`) | | SEC-004 | high | 隐式凭证环境变量读取 (`AWS_*`, `OPENAI_API_KEY`, `GITHUB_TOKEN`) | | SEC-005 | critical | 破坏性 shell 命令 (`rm -rf /`, `dd if=`, `mkfs`, fork bomb) | | SEC-006 | high | 提权 (`sudo`, `chmod 777`, `chown -R root`) | | SEC-007 | high | 隐藏的零宽字符 (U+200B/200C/200D/FEFF) | | SEC-008 | medium | 长 base64 / 高熵 blob(启发式检测) | | SEC-009 | high | Prompt 注入关键词 (`ignore previous instructions`, `jailbreak`) | | SEC-010 | medium | 向非白名单域名发送数据 | | SEC-011 | high | 通过未经清理的变量进行 shell 注入 | | **SEC-012** | **critical** | **Agent 身份 / 记忆文件访问** (`MEMORY.md`, `USER.md`, `SOUL.md`, `IDENTITY.md`, `CLAUDE.md`, `~/.workbuddy/memory`) | | SEC-013 | high | Base64 / 十六进制解码动作 (`base64 -d`, `atob(`, `fromCharCode`) | | SEC-014 | high | 动态执行 (`eval(`, `exec(`, `Function(...)`) | | SEC-015 | high | 对原始 IPv4 地址的网络调用 | | SEC-016 | critical | 浏览器 cookie / 登录数据 / 保存的凭证访问 | | SEC-017 | high | 写入系统 / 特权路径 (`/etc`, `/usr`, `C:\Windows`) | | SEC-018 | high | 反射式动态执行 (`getattr(__builtins__, ...)`, `__import__("builtins").exec`) | | SEC-019 | high | 字符串拼接的 `eval` / `exec` / `compile` 名称 (例如 `'ev'+'al'`) | ### 结构审计 (auditor) `frontmatter`(必填 + 推荐字段),`description`(长度 + 触发措辞),`permissions`(声明的 `allowed-tools` 与检测到的 shell 使用情况的对比),`io_schema`(输入 / 输出部分),`examples`(≥1 个代码块,可运行)。 ### 运行器 示例是被*解释的,而不是被执行的*。运行器使用 `shlex` 和严格的 允许 / 拒绝列表,并且测试套件断言 `subprocess.run`, `Popen`, `check_call` 和 `check_output` 从未被调用。 ## 报告 每份报告都包含(自 0.1.2 起): - **评分 / 风险 / 阈值 / 结果** —— 当评分 ≥ 阈值但存在 HIGH 发现时,具有一个 `⚠️ PASSED WITH CAUTION` 的中间状态。 - **建议操作** —— 基于风险等级映射的指导(例如 CRITICAL → *“DO NOT INSTALL. Address all critical findings first.”*)。 - **权限摘要** —— 从技能主体和示例中自动提取的 *读取文件 / 写入文件 / 命令 / 网络*。 - **清单 / 发现 / 示例预演 / 合规清单**。 ## 评分 ``` score = max(0, 100 - Σ(weight × count)) weights: critical=25, high=12, medium=5, low=2, info=0 ``` 无论评分如何,单个 CRITICAL 发现都会将 `is_passed` 设为 `false`(一票否决)。 CRITICAL 否决同时适用于 `audit_findings` 和 `security_findings`;`is_passed` 是一个 Pydantic v2 `@computed_field`,因此 JSON、 Markdown 和 HTML 报告会自动保持同步。 ## 一行代码搞定 CI ``` skillops init-ci --github-actions ``` 生成 `.github/workflows/skillops.yml`,其中包含**锁定版本**的 `actions/checkout@v4` 和 `actions/setup-python@v5`,一个 artifact 上传步骤,以及一个 `fail-under` 阈值(默认为 `70`)。默认策略拒绝覆盖现有的 workflow;请传递 `--force` 来替换它。 ## 真实案例 在一台开发机器上安装的 37 个技能上运行 SkillOps Forge (`~/.workbuddy/skills/`),发现了两个 **真阳性** CRITICAL 发现: | 技能 | 发现 | 证据 | | --- | --- | --- | | `proactive-agent` | SEC-012 × 2 | `Read SOUL.md` / `Read USER.md` (第 499–500 行) | | `humanizer` | AUD-000 (CRITICAL) | 未加引号的多行 YAML 描述(解析器会优雅降级,而不是崩溃) | 完整分布:2 个 critical · 1 个 high · 3 个 medium · 9 个 low · 22 个 info。 请参阅 `CHANGELOG.md`(条目 `[0.1.2]`, `[0.1.4]`, `[0.2.0]`, `[0.2.1]`)以获取 逐条规则的依据以及对 skilllint 和 skillcheck 的现有技术致敬。 ## 设计红线 1. **永不使用 `subprocess`** —— 运行器没有导入任何 `subprocess`;测试 使用 monkey-patch 并断言未被调用。 2. **完全离线** —— 没有任何网络调用(甚至不调用 GitHub API);`init-ci` 只写入模板文件。 3. **永不上传用户内容** —— 分析的每一个字节都保留在本地。 4. **永不执行危险命令** —— 示例通过 `shlex` 以及允许 / 拒绝列表进行解释;`curl … | sh` 会被拦截。 5. **风险辅助,而非认证** —— 每份报告中都有明确的免责声明。 ## 项目结构 ``` skillops-forge/ ├── src/skillops_forge/ │ ├── parser/ # SKILL.md / CLAUDE.md / .cursor/rules │ ├── auditor/ # frontmatter / description / permissions / io / examples │ ├── scanner/ # rule loader + dedup engine │ ├── runner/ # shlex-based dry-run, never subprocess │ ├── reporter/ # md / html / json + scoring │ ├── pipeline.py # parser → audit → scan → run → score → report │ ├── plugins/ # PluginProtocol (P1: LLM judge, cross-format export) │ ├── rules/ # YAML data-driven SEC rules │ ├── templates/ # Jinja2 (HTML/MD reports + GH Actions yaml) │ └── ci/ # init-ci generator ├── tests/ # 206 tests, 91% line coverage (scanner ≥95%) ├── docs/ # architecture, rules, JSON schema, mermaid diagrams └── pyproject.toml ``` ## License [](LICENSE) · 中文版见 [README_CN.md](README_CN.md).
标签:代码质量检查, 逆向工具, 错误基检测, 静态代码分析