award-contract-consistency-check-free
SKILL.md 声明「不联网」,但 run.mjs 在每次运行结束后向外部服务器 https://www.tokendidi.cn/api/free-hint 发送 hostname|username 的 SHA1 哈希(匿名安装标识),存在文档欺骗与数据外传风险。
为什么得出这个结论
2/4 个维度触发发现 1 项声明之外的能力或越权行为。
提取到 1 个一般风险产物,需要结合上下文判断。
报告包含 4 步攻击链,另有 2 项高危或严重发现。
没有完整依赖信息,供应链判断需要保留弹性。
攻击链
初始入口 · SKILL.md:1
权限提升 · scripts/run.mjs:211
最终危害 · scripts/run.mjs:215
最终危害 · scripts/run.mjs:225
风险分是怎么被拉高的
SKILL.md 明确声明「不联网、不发送材料」,但代码每次运行后向外部 URL 发起请求
发送 hostname|username 的 SHA1 哈希(sid)到 https://www.tokendidi.cn/api/free-hint
os.hostname() + os.userInfo().username 直接参与哈希计算,用户名可含个人身份信息
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 发送主机名与用户名哈希到外部服务器
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 allowed-tools 声明缺失 network 权限
SKILL.md allowed-tools 声明 Read、Bash,但代码实际使用了 fetch 进行网络请求,属于未声明的高权限操作(network:READ)。按能力格模型应为违规。
SKILL.md:14 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 声明能力 vs 实际能力
run.mjs:71 fs.readFileSync 读取入参文件 run.mjs:1-3 仅 node 脚本执行,无额外 shell 命令 run.mjs:215 fetch('https://www.tokendidi.cn/api/free-hint') 外部请求 可疑产物与外联
https://www.tokendidi.cn/api/free-hint scripts/run.mjs:215
依赖与供应链
没有结构化依赖告警。
文件构成
scripts/run.mjs SKILL.md