DeepSeek Harness Hub
← 返回列表

whaojie797-design/skill-sentry

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

在让一个 Skill 读取你的机器之前,先读懂它。

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/30 · 已提供中文文档

针对 Agent Skills 的静态、本地、可解释的安装前安全审计。扫描 SKILL.md/脚本/配置,以发现破坏性命令、隐藏网络调用、密钥读取、混淆、提示注入、持久化。CLI + 36 个测试夹具 + GitHub Actions。

综合分
28.1
GitHub 分
28.1
用户评分
★ Stars
0
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add whaojie797-design/skill-sentry
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/17(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

在让一个 Skill 读取你的机器之前,先读懂它。
在让一个 Agent Skill 碰你的电脑之前,先读懂它。

License: MIT
Python
Tests
Dependencies
Topics

skill-sentry 是面向 AI Agent 的信任层:一个本地、静态、离线的工具,
覆盖第三方 Agent Skill 的整个生命周期。

skill-sentry 是面向 AI Agent 的信任层:一个本地、静态、离线的工具,覆盖第三方
Agent Skill 的整个生命周期。

| 阶段 / 阶段 | 命令 | 你得到什么 / 你得到什么 |
|---|---|---|
| 安装前审计 / 安装前审计 | audit | 一份带有 file:line 证据的风险报告 |
| 运行前锁定 / 运行前锁定 | lock | 一个 SHA-256 证据基线(skill-sentry.lock.json) |
| 交接时可验证 / 交接时可验证 | verify | 针对基线的逐文件差异,每条发现都带有 path |
| 改动后可追溯 / 改动后可追溯 | verify | 每个漂移条目的改动前/后哈希 |

它不会执行被扫描的 Skill、不会联网、不读环境变量、不上传任何内容。

它不会执行被扫描的 Skill、不会联网、不读环境变量、不上传任何内容。

3 分钟快速开始 / 3 分钟快速开始

git clone https://github.com/whaojie797-design/skill-sentry
cd skill-sentry
python --version          # 3.9 或更新 / 需要 3.9 及以上

无需安装任何依赖——零第三方依赖,纯 Python 标准库。

无需安装任何依赖——零第三方依赖,纯 Python 标准库。

1) 审计一个你正准备安装的 Skill / 审计一个你正准备安装的 Skill
python scripts/skill_sentry.py audit ./some-skill

2) 觉得没问题就锁定基线 / 觉得没问题就锁定基线
python scripts/skill_sentry.py lock ./some-skill

3) 交接后、更新后、一周后再校验 / 交接后、更新后、一周后再校验
python scripts/skill_sentry.py verify ./some-skill

audit 输出到 SKILL_AUDIT.md / skill-sbom.json / policy-result.json。
lock 写入 skill-sentry.lock.json。verify 写入 VERIFY_REPORT.md 和
verify-report.json,并将同一份报告打印到 stdout。

旧版 v0.1.0 入口点的行为与之前完全一致:

python scripts/audit_skill.py ./some-skill            # 行为不变 / 行为不变

真实示例 / 真实示例

以下命令在一份 4 文件的 demo Skill 上真实执行
(SKILL.md、scripts/run.py、scripts/helper.sh、assets/logo.png),
并带有一个 skill 内的 policy.yml。下面的输出为逐字捕获,
不是编造的示例。

以下命令在一份 4 文件的 demo Skill 上真实执行(SKILL.md、scripts/run.py、
scripts/helper.sh、assets/logo.png + skill 内的 policy.yml)。输出为逐字捕获,
不是编造的示例。
捕获说明:输出来自 Windows(/tmp 对应本机的 C:\temp)。
在 Linux / macOS 上,只有路径分隔符与路径不同,其余内容一致。

lock

$ python scripts/skill_sentry.py lock demo-skill --policy demo-skill/policy.yml
skill-sentry 0.2.0 - lock
========================================================================
Lock file    : C:\temp\demo-skill\skill-sentry.lock.json
Skill        : demo-skill
Files        : 4 (text=3 binary=1 unknown=0 symlink=0)
Rule-scanned : 3
Empty dirs   : 0
Warnings     : 0
Policy       : source=explicit present=True external=False
Audit        : policy_passed=True max_level=INFO findings=0
Integrity    : sha256 files_hash=cceb3b2961f160df65453a277dcbbc7902280daddd4e93a3eb82df9fb65e60a6
Limits       : max_file_size=26214400 follow_symlinks=False

This lock file is a baseline, NOT a safety guarantee.
该锁文件是基线证据,不是安全保证。
Commit it with the skill, or store it outside the skill directory.
请与 skill 一起提交进 Git,或用 --lock-out 保存到 skill 目录之外。
========================================================================
echo $?
0

lock 即使基线不完整也会写入文件,因此 verify 始终有可比较的对象。对未改动的 Skill 连续运行两次 lock,除 generated_at 外会产生字节完全一致的输出。

即使基线不完整,lock 也会落盘(这样 verify 永远有可比对象)。对未改动的 Skill
连续执行两次 lock,除 generated_at 外字节完全一致。

verify — 未改动

$ python scripts/skill_sentry.py verify demo-skill
skill-sentry 0.2.0 - verify
========================================================================
Result       : OK (exit 0) / 与基线一致(退出码 0)
Lock file    : C:\temp\demo-skill\skill-sentry.lock.json
Skill dir    : demo-skill
Findings     : error=0  review=0  info=0  unverifiable=0  fatal=0

What "verify passed" means / "verify 通过"到底意味着什么
verify PASS = "this skill still matches the recorded baseline".
verify PASS != "this skill is safe".
If any entry is UNVERIFIABLE, it is NOT counted as unchanged.
verify 通过 = 「与锁定时的记录一致」。
verify 通过 ≠ 「这个 Skill 是安全的」。
若有条目无法判定(UNVERIFIABLE),本报告不会把它算作「未漂移」。

Findings / 发现(0 条)
No findings: this skill matches the recorded baseline.
未发现差异:当前内容与锁定基线一致。
========================================================================
wrote: C:\temp\demo-skill\VERIFY_REPORT.md
wrote: C:\temp\demo-skill\verify-report.json
echo $?
0

verify — 有人改了一个文件之后

将 scripts/run.py 中的 total = sum(range(10)) 改为 sum(range(11)):

$ python scripts/skill_sentry.py verify demo-skill --no-write
skill-sentry 0.2.0 - verify
========================================================================
Result       : DRIFT (exit 1) / 检测到漂移(退出码 1)
Lock file    : C:\temp\demo-skill\skill-sentry.lock.json
Skill dir    : C:/temp/demo-skill
Findings     : error=1  review=0  info=0  unverifiable=0  fatal=0

What "verify passed" means / "verify 通过"到底意味着什么
verify PASS = "this skill still matches the recorded baseline".
verify PASS != "this skill is safe".
若任一条目为 UNVERIFIABLE,则不计入「未变更」。
verify 通过 = 「与锁定时的记录一致」。
verify 通过 ≠ 「这个 Skill 是安全的」。
若有条目无法判定(UNVERIFIABLE),本报告不会把它算作「未漂移」。

Findings / 发现(1 条)
[ERROR] FILE_MODIFIED  scripts/run.py
content differs from the locked baseline
expected: 24b1ff2afa92d9bbcd0b6c43399aa5463d49600b59895e40dc7180b94e15ca72
actual:   1ebcbc3173f3a41516833b37ccd41a7079abea772de71a909452ed1dfa34ea5f

Every finding above carries a path so it can be located in the diff.
上面每一条发现都带有 path,可在 diff 中直接定位。
========================================================================
echo $?
1

Exit codes / 退出码

每条命令都使用相同的四个退出码。任何非零退出码都应视为「不要信任这个 Skill」。

| 退出码 | Meaning / 含义 | 触发条件 |
|---|---|---|
| 0 | OK | 无漂移,且全部可判定 / no drift, everything judged |
| 1 | DRIFT | 确认漂移,或配合 --fail-on-policy 时的策略失败 |
| 2 | ERROR | 无法完成:目录缺失、锁文件不可读/损坏/不兼容、IO 失败 |
| 3 | UNVERIFIABLE | 无漂移,但部分条目无法判定 |

优先级恒为 2 > 1 > 3 > 0。退出码 3 存在的意义是:「判不出来」绝不能被报成「没变」。

What audit checks / audit 检查什么

| 领域 | 规则 | 捕获内容 |
|--------|-------|---------|
| Destructive | DEST | rm -rf /、清空 home、fork bomb、磁盘覆写 |
| Network | NET | 出站请求、下载并执行的管道(curl … \| sh) |
| Secrets | SECRET | SSH 目录、私钥、AWS 凭据、token 模式、环境变量收集 |
| Obfuscation | OBF | Base64 解码、动态求值、反射 |
| Injection | INJ | 「忽略之前的指令」、「绕过安全机制」、「不要告诉用户」 |
| Persistence | PERSIST | shell 启动文件、cron、launch agents、systemd |
| Filesystem | FS | 写入 /etc、/System、个人目录 |
| Domains | DOMAIN | 引用的每个外部主机(SBOM) |

每次命中都会报告 file:line、rule_id、原因、置信度和级别
(INFO / REVIEW / HIGH)。启发式命中不是已确认的
漏洞——HIGH 级别的命中始终需要人工复核。

Threat model summary / 威胁模型摘要

完整模型见 references/threat-model.md。

What it protects against / 能防什么

| ID | 威胁 | 方式 |
|---|---|---|
| T1 | 安装后被静默添加或替换的代码 | lock 记录哈希基线;verify 报告带路径的 FILE_ADDED / FILE_MODIFIED |
| T2 | 通过「更新」夹带的恶意代码 | 同上,另加 --reaudit 以比较审计摘要 |
| T3 | TOCTOU:被审计的版本 ≠ 实际运行的版本 | 锁文件将审计结论与文件哈希绑定在同一个产物中 |
| T4 | 策略被悄悄放宽,使旧的 PASS 失效 | 记录 policy.sha256;verify 报告 POLICY_CHANGED |
| T5 | 无法证明“这就是我审查过的内容” | 锁文件是可 diff、可提交的证据 |
| T6 | 新的未声明网络目标 | audit.domains 被锁定;--reaudit 会比较该列表 |
| T7 | 符号链接将宿主机文件拖入范围 | 默认从不跟随符号链接;记录 link_target 以供审查 |
| T8 | 使用超大或二进制文件耗尽工具资源 | 流式哈希、25 MiB 规则扫描阈值,二进制文件只做哈希但不解析 |

What it does NOT protect against / 不防什么(节选——请阅读完整文件)

| ID | 不防护 | 原因 | 本工具之外的缓解措施 |
|---|---|---|---|
| N1 | 被攻陷的宿主机 | 拥有同等文件权限的攻击者可以编辑 Skill、锁文件和工具本身 | 操作系统完整性保护、只读挂载、最小权限 |
| N2 | 锁文件与 Skill 一起被编辑 | 默认情况下锁文件位于 Skill 旁边,且未签名;它不是信任根 | 在 Skill 之外使用 lock --lock-out;保护 Git 分支;外部签名(v3 正在评估) |
| N3 | 运行时行为 | 纯静态:无沙箱、无系统调用过滤、无网络监控 | 容器 / 沙箱 / seccomp |
| N4 | 意图 | 它只能说“与基线不同”,永远不能说“此更改是恶意的” | 人工审查 diff |
| N5 | 作者身份与来源 | 无签名、无证书 | Sigstore / minisign 正在为 v3 评估 |
| N6 | 归档文件和二进制文件的内容 | .zip 内的载荷不可见;只有 .zip 的哈希会变化 | 手动解包并审查 |
| N7 | 密码学绝对性 | SHA-256 抗碰撞性是工程假设,而且没有签名 | — |
| N8 | 实时信誉 | 它无法判断某个域名现在是否恶意 | 外部威胁情报 |
| N9 | 运行时注入的机密 | 它有意从不读取环境 | 单独审计运行时环境 |
| N10 | 规则引擎的误报/漏报 | 命中不等于漏洞;未命中不等于安全证明 | 人工审查;参见误报处理手册 |

The one sentence to remember / 务必记住的一句话

verify 通过 = 「与锁定时的记录一致」
verify 通过 ≠ 「这个 Skill 是安全的」
若有条目无法判定(UNVERIFIABLE),本报告不会把它算作「未漂移」。

每份 verify 报告每次都会以两种语言打印这句话。

Honest limitations / 诚实的局限

- It does not guarantee that any Skill is safe. /
它不保证任何 Skill 的安全性。
- It does not execute the scanned Skill. / 它不会执行被扫描的 Skill。
- It does not upload anything, ever. / 它从不上传任何内容。
- A heuristic hit is not a confirmed vulnerability. /
启发式命中不等于已确认的漏洞。
- A clean verify means "matches the baseline", not "is safe". /
verify 通过只意味着「与基线一致」,不意味着「安全」。
- The lock file is not signed in v2; anyone who can edit the Skill can edit
it. See N2 above. / v2 的锁文件未签名,能改 Skill 的人就能改它(见上文 N2)。
- Symlink targets are recorded but not compared, because they are
environment specific (see the threat model). /
符号链接的目标会被记录但不参与比对,因为它与环境相关。

Command reference / 命令参考

python scripts/skill_sentry.py audit   [--policy P] [--out DIR]

python scripts/skill_sentry.py lock
[--policy P]            policy file to record (its SHA-256 is stored)
[--lock-out PATH]       lock file path (default: /skill-sentry.lock.json)
[--max-file-size N]     rule-scan threshold in bytes (default 26214400 = 25 MiB)
[--follow-symlinks]     follow symlinks that stay inside the Skill (default: off)
[--no-audit]            skip the audit section (audit = null)
[--fail-on-policy]      exit 1 when the audit fails the policy
[--indent N]            JSON indent (default 2; 0 = compact)
[--quiet]               errors only

python scripts/skill_sentry.py verify
[--lock PATH]           lock file path (default: /skill-sentry.lock.json)
[--policy PATH]         policy that overrides the one recorded in the lock
[--out DIR]             report directory (default: the lock file's directory)
[--md-out PATH] [--json-out PATH]
[--no-write]            print only; write nothing
[--check-audit]         treat audit-summary changes as drift (exit 1)
[--reaudit]             re-run the rule engine and compare the summary
[--ignore-empty-dirs]   ignore added/removed empty directories
[--allow-unverifiable]  record unverifiable entries but keep exit code 0
[--quiet]

--follow-symlinks is documented as "only use it when you fully trust this
Skill": following a symlink means hashing content that lives outside the Skill
directory. The containment check (the resolved target must stay under the Skill
root) still applies.

--follow-symlinks 的文档说明是「仅在你能完全信任该 Skill 时使用」:跟随符号链接
意味着哈希 Skill 目录之外的内容。即使开启,仍会强制「解析后目标必须仍在 Skill 根目录内」。

Install as an Agent Skill / 作为 Agent Skill 安装

Each host installs Skills on its own / 各宿主自行安装:

Claude Code
git clone https://github.com/whaojie797-design/skill-sentry ~/.claude/skills/skill-sentry
Cursor
git clone https://github.com/whaojie797-design/skill-sentry ~/.cursor/skills/skill-sentry
Codex / OpenAI
git clone https://github.com/whaojie797-design/skill-sentry ~/.codex/skills/skill-sentry
Gemini CLI
git clone https://github.com/whaojie797-design/skill-sentry ~/.gemini/skills/skill-sentry

CI / 持续集成

- name: Verify Skills have not drifted
run: |
python scripts/skill_sentry.py lock  ./skills/my-skill --lock-out build/my-skill.lock.json
python scripts/skill_sentry.py verify ./skills/my-skill --lock build/my-skill.lock.json

Storing the lock file outside the Skill directory (--lock-out) is the
更强的配置:对 Skill 的改动无法静默改写它自己的基线。详见 SECURITY.md。

把锁文件存到 Skill 目录之外(--lock-out)是更强的配置:对 Skill 的改动无法顺手
改写它自己的基线。详见 SECURITY.md。

零依赖 / Zero dependencies

运行时依赖:无。仅使用 Python 标准库
(argparse、dataclasses、hashlib、json、os、sys、stat、datetime、
platform、typing),代码面向 Python 3.9+。pytest 仅为测试期依赖。

运行时依赖:无。只用标准库,目标 Python 3.9+。pytest 仅为测试期依赖。

源码由 tests/test_guards.py 守护,该文件静态断言
没有任何模块导入 socket / urllib.request / http.client / subprocess,
从不调用 eval( / exec(,也从不读取 os.environ / os.getenv。

资源 / Resources

- references/lock-file-schema.md — 逐字段 schema、演进规则、兼容性承诺
- references/threat-model.md — 完整威胁模型
- references/rule-catalog.md — 每条规则 ID 及其含义
- references/false-positive-playbook.md — 如何分诊命中项
- assets/skill-sentry.lock.example.json — 一个真实的锁文件
- assets/VERIFY_REPORT.example.md — 一份真实的验证报告
- assets/policy.example.yml — 团队策略模板
- CHANGELOG.md — 发布历史
- SECURITY.md — 漏洞披露
- docs/DESIGN-v2.md — v2 设计文档

许可证

MIT — Copyright (c) 2026 whaojie797-design。

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群