安全修复:复合命令缺口、状态文件投毒、自批命令、协议 fail-open、dangerlist 漏报

- COMPOUND 补全换行/单个&/重定向(白名单不再被多行/重定向命令绕过),find 移出白名单
- gatekeeper 状态文件读写确定性硬拒(防 approved.json 投毒绕过灾难黑名单)
- 模型自批 approve 命令确定性硬拒(防 --yes 自我放行)
- approvedConsume 校验时间戳必须在过去(防未来时间戳使批准永不过期)
- daemon 协议错误/未知 op 返回 {ok:false},客户端降级内联完整审查(消除 fail-open)
- onReviewerError 支持 prompt 别名;llmTimeoutMs 超时预算钳制(防 hook 超时 fail-open)
- dangerlist 补漏:del/rd flag 顺序无关、Remove-Item 盘根星号、Format-Volume、format.com
- review 输入 JSON 解析失败与基础设施崩溃改为 fail-closed
- install 首次安装从模板生成 config.json;回归扩展至 41 项
This commit is contained in:
luoxiaoxin123
2026-09-13 20:59:36 +08:00
parent d1188c8eef
commit b207dbcaa0
8 changed files with 99 additions and 20 deletions
+13 -3
View File
@@ -108,8 +108,10 @@ async function proxyOrStartDaemon(port, mode, payload) {
return tryProxy(port, { op: 'hook', mode, payload, sigs: sigs(), env: { fullAccessGuard: ['1', 'true', 'yes', 'on'].includes(String(process.env.GATEKEEPER_FULL_ACCESS_GUARD || '').toLowerCase()) ? true : undefined } }, 42_000);
}
const HOOK_MODE = process.argv[2] || '';
async function main() {
const mode = process.argv[2] || '';
const mode = HOOK_MODE;
// ---- 管理命令(不读 stdin,即秒响应)----
if (['install', 'uninstall', 'enable', 'disable', 'status', 'approve', 'shutdown-daemon'].includes(mode)) {
@@ -123,6 +125,12 @@ async function main() {
let payload = null;
try { payload = JSON.parse(raw); } catch { payload = null; }
// review 模式下输入必须可解析(fail-closed):schema 漂移/截断时宁可拒绝也不放行
if (mode === 'review' && payload == null) {
exitWith(2, '', '【Auto 审批员·拒绝】hook 输入不是有效 JSON,安全起见拒绝执行(fail-closed)。\n');
return;
}
const cfg = loadJsonFile(path.join(SCRIPT_DIR, 'config.json'), {});
const daemonEnabled = cfg.daemon !== false && !process.env.GATEKEEPER_NO_DAEMON;
const port = cfg.daemonPort | 0 || 47811;
@@ -142,9 +150,11 @@ async function main() {
}
main().catch(e => {
// review 模式下基础设施崩溃按"拒绝"处理(fail-closed);其余模式按普通错误
const code = HOOK_MODE === 'review' ? 2 : 1;
process.stderr.write('【Auto 审批员·异常】' + (e?.message || String(e)) + '\n');
try { process.stdin.destroy(); } catch { /* 忽略 */ }
process.exitCode = 1;
const t = setTimeout(() => { try { process.exit(1); } catch { /* 忽略 */ } }, 250);
process.exitCode = code;
const t = setTimeout(() => { try { process.exit(code); } catch { /* 忽略 */ } }, 250);
if (typeof t.unref === 'function') t.unref();
});