Repository navigation
fix: 安全审计加固(基于 #1)+ 凭据名字规则与目录收紧日志 - #2
Open
kyomarshal wants to merge 5 commits into
Open
kyomarshal wants to merge 5 commits into
kyomarshal wants to merge 5 commits into
Conversation
外部安全审计 D4、D9-③ 在代码与 mock 上核实属实后的修复。 D4:runner 是从宿主代理里起的,环境里常有 ANTHROPIC_API_KEY、GITHUB_TOKEN 一类 凭据;zcode 子进程原样继承,执行端的 Bash 一条 env 就全看见,配上联网工具就能外发。 拉起子进程时按固定名单剔掉(不做白名单:HOME、PATH 漏一个就坏功能),不论它来自 本进程环境还是调用方的 opts.env——doctor 与闲时自检是把 process.env 整份传进来的, 只剔继承来的那一份会漏。没带过去的名字在 stderr 说一行,只有名字。 D9-③:去重表从不清理,对端一旦复用 requestId,上一回合缓存的放行会原样答给新请求, 处理器(闸门)根本不跑。mock 复现:第二回合换了命令、同一个 requestId,旧实现直接 回 allow。现在 Session.send 开头清掉已出结果的条目。没有 requestId 的退路键从 「方法|会话」改成「方法 + 参数全文」:同会话里第二个无 requestId 的审批请求不再并进 第一个、拿到它的放行;重发的参数一字不差,仍落进同一键,处理器不会被重发反复叫起。 另:events.jsonl 与所在目录新建时只给当前用户(审计 D5 落在协议层的部分)。 mock 加三个剧本字段:reportEnv、serverRequests[].omitRequestId、permission.requestId。 用例 728 → 731。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
外部安全审计 D9-① 核实属实:挂起回显把工具名、理由原样打到终端,执行端在里面夹一段 ANSI/OSC 转义就能清行、回车改写人正在看的那行审批、改窗口标题。回复原文、流式行、 文件名摘要、zcode 报错原文同样是执行端可控的文本,打印点有几十处。 逐处过滤迟早漏一处,所以在入口把 stdout / stderr 的写出口包一层:C0(换行、制表除外)、 DEL、C1(8 位的 CSI/OSC,JSON.stringify 不转义它们)、双向排版控制符,一律换成字面的 \uXXXX——内容不丢,人能看出这里被塞了东西。\r\n 收成 \n,落单的 \r 照样转义。 --json 的含义不变:这些字符只会出现在 JSON 字符串里,\uXXXX 在那里是合法转义, 解析回来还是原字符。runner.log 走的是同一个入口,一并中和。 拦不了的:模型回复里自己写一行「send: done」。回复原文按原样分行打印是定下来的做法。 用例 731 → 736(纯函数与写出口包装;走真实 CLI 的两条随下一个提交进 run.test)。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
外部安全审计 D1、D2、D3 及 D5、D6、D8、D9-②、D9-④ 逐条在代码与本机上核实后的修复。 每条先补失败用例再改;新加的检查失败方向都是转人工,没有哪条 ask 路径被改成自动放行。 D1(越界红线可绕):原先 path.resolve 之后再 realpathSync,<执行副本>/link/../x 先被 词法折叠成看着在界内的路径,实际写入落在链接目标的上一级——Node 的 realpathSync 自己 也是先折叠。改成从根逐段解析(符号链接就地展开,.. 退到真实父目录,末段的悬空链接也 跟),原串与词法归一后的串各算一遍,任一越界即命中。成环、把文件当目录穿这类判不了 落点的,以及写类工具(含 3.14.4 的保留名 ApplyPatch)拿不出可判路径的,不再当界内放过。 D2(执行端能自己批自己):执行端与 runner 是同一个用户,写 answer.json、跑 zcode-executor approve,文件权限与属主校验都挡不住。新增机械红线 self-modify-approval: 操作指向本工具的数据目录或调本工具的 CLI,直接转人工,不交给模型判。审计说「匹配数据 目录前缀不会误伤」在这里不成立——默认的执行副本就在 <数据目录>/worktrees 下——所以放行 worktrees/ 与本会话的 cwd,CLI 只认名字后面跟子命令。只认直白写法;拼变量、先写脚本 再跑认不出来,同一个用户之下没有根治(decisions D23)。 D3(任务单可事后改写):审批把任务单当「用户说过的话」,却在每次审批时现读执行副本里 那份执行端改得动的文件。入队时留快照(runs/<id>/tasks/<sha256>.md),审批只按事件里的 taskSha256 读快照并核对哈希;没有快照的旧事件不再作依据(只会更常转人工)。闲时投递 先取号后入队,所以在取号之前先留一份,任务单读不了不白用一次号。 其余:runs/ 树 0700、落盘 0600,pending.json 按值抹掉 runner 手里的密钥(D5;不做 启发式脱敏,人要靠原文决定放不放);原子写的临时名加随机段并排他创建(D9-②); 审批探针的 git 关掉 fsmonitor、钩子、外部 diff、textconv,并把仓库配置里的 filter 驱动逐个置空(D6;filter 这条审计没提,是核实时在 git 2.54.0 上实测出来的); 快筛只认独立成词且唯一的 Y,「They are…」里的 y 不再算放行(D8)。 没改的与理由见 decisions D23:慢判提示词不套启发式脱敏(D7)、Write 正文仍进快筛 (D8 后半)。 用例 736 → 765。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
同步已落地的安全加固行为、术语与验收数量。按本机 ZCode 3.14.4 的源码核对联网工具的注册与屏蔽,明确工具禁用和系统断网的边界,避免把局部加固写成完整隔离。
基于 #1 的评审意见(御史): - lib/appserver.mjs:固定名单之外,按名字后缀 _TOKEN/_KEY/_SECRET(不分大小写)剔除宿主凭据,ZCODE_ 开头的自家配置不剔;补 AWS 两项 - lib/runs.mjs:ensureRunsDir 的 chmod 失败不再静默,经 onWarn(默认 stderr)记一行 - 测试:appserver 用例覆盖名字规则;新增 test/runs-dir.test.mjs;stderr 首行断言改为按内容找
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
基于 #1(@hezhongtang 的安全审计加固)继续,保留原作者 4 个提交,rebase 到最新 main,再按评审(御史)意见补两点。#1 保持打开,不在本 PR 里合并或关闭。
Rebase
有冲突,已手工解决:
lib/queue.mjs/lib/run.mjs:fix: 安全审计加固 / Harden the permission gate and runner #1 的任务单快照(taskSha256、ensureRunsDir、0700)与 main 的 start plan 投递(startPlan 字段、startplan runner)两边合并,都保留。lib/review/hard.mjs:采用 fix: 安全审计加固 / Harden the permission gate and runner #1 的内核走法判界(resolveLikeKernel + 闸门自保),并把 main 新加的「系统临时目录放行」移植进去(tmp 根同样按内核走法解析后判前缀)。AGENTS.md、README*.md、skills/zcode-executor/SKILL.md:以 main 为准(v0.5.2、新版审批流程),补回 fix: 安全审计加固 / Harden the permission gate and runner #1 的 D23 状态说明和self-modify-approval提示。两点改动(提交 809a3d2)
lib/appserver.mjs,新增导出isHostCredentialEnv,AppServerClient.spawn里用)名单之外,名字以
_TOKEN/_KEY/_SECRET结尾(不分大小写)的环境变量一律不带给 zcode 子进程;ZCODE_开头的不剔(如ZCODE_CREDENTIAL_SECRET是 zcode 解凭据文件要用的)。名单另补AWS_SECRET_ACCESS_KEY、AWS_SESSION_TOKEN。为什么没改成白名单:子进程要的是用户的完整工作环境(HOME、PATH、代理、locale、各类工具链变量),白名单漏一个就让执行端的 Bash 跑不通,且很难穷举;按名字规则剔除覆盖了“名单外新冒出来的凭据”这个实际风险,同时不动正常变量。剔掉的仍只在 stderr 报名字、不报值。
lib/runs.mjs的ensureRunsDir)chmod 0700 失败不再静默:照旧不拦投递,但经
onWarn(默认写 stderr,进 runner.log)记一行,带错误码和目录路径。测试
npm test:803 个用例,801 通过,0 失败,2 跳过(原本就跳过的),文档版本号检查通过。test/appserver.test.mjs:凭据用例加了按名字规则剔除的变量(含小写)和应保留的变量(*_TOKENIZER、ZCODE_*_SECRET)。test/runs-dir.test.mjs:收紧成功不警告;chmod 失败不抛、每个目录记一行警告。子进程 stderr 经 onStderr 收到…用例原先断言 stderr 第一行,宿主环境里有凭据形状的变量时第一行会是“没带给 zcode”的说明,改成按内容找。README 里的用例数徽章(764)没改,等发版时统一更新。