安全决策报告

award-contract-consistency-check-free

SKILL.md 声明「不联网」,但 run.mjs 在每次运行结束后向外部服务器 https://www.tokendidi.cn/api/free-hint 发送 hostname|username 的 SHA1 哈希(匿名安装标识),存在文档欺骗与数据外传风险。

安装决策优先 来源: ClawHub 扫描时间: 2026/9/19
文件 4
IOC 1
越权项 1
发现 4
最直接的威胁证据
01
用户通过 SKILL.md 了解技能,误以为完全本地运行不联网 初始入口 · SKILL.md
02
运行 node scripts/run.mjs --input xxx.json,触发 hintAfterRun() 权限提升 · scripts/run.mjs
03
hostname|username 的 SHA1 哈希被发送到 https://www.tokendidi.cn/api/free-hint 最终危害 · scripts/run.mjs

为什么得出这个结论

2/4 个维度触发
阻止
声明与实际能力

发现 1 项声明之外的能力或越权行为。

复核
隐藏执行与外联

提取到 1 个一般风险产物,需要结合上下文判断。

阻止
攻击链与高危发现

报告包含 4 步攻击链,另有 2 项高危或严重发现。

复核
依赖与供应链卫生

没有完整依赖信息,供应链判断需要保留弹性。

攻击链

01
用户通过 SKILL.md 了解技能,误以为完全本地运行不联网

初始入口 · SKILL.md:1

02
运行 node scripts/run.mjs --input xxx.json,触发 hintAfterRun()

权限提升 · scripts/run.mjs:211

03
hostname|username 的 SHA1 哈希被发送到 https://www.tokendidi.cn/api/free-hint

最终危害 · scripts/run.mjs:215

04
服务端返回的 message 内容打印到 stderr,可能含注入指令

最终危害 · scripts/run.mjs:225

风险分是怎么被拉高的

文档声明-实际行为不符 +30

SKILL.md 明确声明「不联网、不发送材料」,但代码每次运行后向外部 URL 发起请求

外部数据外传 +20

发送 hostname|username 的 SHA1 哈希(sid)到 https://www.tokendidi.cn/api/free-hint

敏感标识符发送 +15

os.hostname() + os.userInfo().username 直接参与哈希计算,用户名可含个人身份信息

allowed-tools 声明缺失 +10

allowed-tools 声明 Read+Bash,但实际使用了 fetch(网络请求),属于越权

最关键的证据

高危 文档欺骗

SKILL.md 声明不联网但实际存在外部网络请求

SKILL.md 多处声明「完全本地运行」「不联网」「不发送材料」「不写任何文件」,但 scripts/run.mjs 第 215 行在 main() 结束后调用 hintAfterRun(),向 https://www.tokendidi.cn/api/free-hint 发起 fetch 请求。这是典型的文档-行为不符(文档欺骗)。

scripts/run.mjs:215
在 SKILL.md 中声明 network 权限,说明发送的字段(id、sid)及用途(匿名次数统计),不得隐瞒外部通信。
高危 数据外泄

发送主机名与用户名哈希到外部服务器

run.mjs 第 219-220 行:const sid = crypto.createHash('sha1').update(`${os.hostname()}|${(os.userInfo() || {}).username || ''}`).digest('hex').slice(0, 16); 将 hostname|username 拼接后 SHA1 哈希取前 16 字符作为 sid,发送至外部 API。username 可能含个人身份信息,SHA1 无法完全消除关联风险。

scripts/run.mjs:219
使用更随机的标识符(如设备指纹或完全随机的 nonce),避免使用用户名等可关联个人身份的信息;或在文档中明确说明此为匿名安装标识。
中危 权限提升

allowed-tools 声明缺失 network 权限

SKILL.md allowed-tools 声明 Read、Bash,但代码实际使用了 fetch 进行网络请求,属于未声明的高权限操作(network:READ)。按能力格模型应为违规。

SKILL.md:14
将 allowed-tools 改为 Read, Bash, WebFetch 以匹配实际使用的网络能力。
低危 提示注入

free-hint 响应内容直接输出可能含注入内容

run.mjs 第 225 行:if (j && j.show && j.message) console.error('\n' + j.message); 若服务端返回恶意 message 内容,会被打印到 stderr,可能含 ANSI 转义序列或提示词注入指令。风险较低(输出到 stderr 非 stdout),但需注意。

scripts/run.mjs:225
对服务端返回的 message 进行内容过滤或转义,避免 ANSI 注入。

声明能力 vs 实际能力

文件系统 通过
声明 READ
→
推断 READ
run.mjs:71 fs.readFileSync 读取入参文件
命令执行 通过
声明 WRITE
→
推断 WRITE
run.mjs:1-3 仅 node 脚本执行,无额外 shell 命令
网络访问 阻止
声明 NONE
→
推断 READ
run.mjs:215 fetch('https://www.tokendidi.cn/api/free-hint') 外部请求

可疑产物与外联

中危 外部 URL
https://www.tokendidi.cn/api/free-hint

scripts/run.mjs:215

依赖与供应链

没有结构化依赖告警。

文件构成

4 个文件 · 639 行
JavaScript 2 个文件 · 558 行Markdown 1 个文件 · 78 行JSON 1 个文件 · 3 行
需关注文件 · 2
scripts/run.mjs JavaScript · 249 行
SKILL.md 声明不联网但实际存在外部网络请求 · 发送主机名与用户名哈希到外部服务器 · free-hint 响应内容直接输出可能含注入内容 · https://www.tokendidi.cn/api/free-hint
SKILL.md Markdown · 78 行
allowed-tools 声明缺失 network 权限
其他文件 · award-contract-consistency-check.js · sample.json

安全亮点

纯 Node 标准库实现,无第三方依赖,不存在供应链风险
材料不足时不给结论,行为符合文档承诺
引擎代码结构清晰,检查项与文档声明基本一致
文件大小适中(26.8KB),无明显混淆或膨胀