oh-my-openagent 安全评审阻塞项全解:RPC 子进程树回收与构建产物完整性防护实战
oh-my-openagent 安全评审阻塞项全解RPC 子进程树回收与构建产物完整性防护实战【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent导读本文以 oh-my-openagent 仓库中 PR #6858 安全评审产生的阻塞项证据文档 security-blockers.md 为骨架完整还原该次评审暴露出的四个安全缺陷及其修复方案RPC 子进程树无法被彻底终止、生成式构建产物新鲜度标记可被伪造、相对可执行路径可被任务控制的工作目录劫持以及相应的全量回归验证。读完本文你将掌握进程组级终止、可复现压缩、防伪造完整性标记、路径规范化等一整套可复用到任意 Node/Bun 工具链的进程安全与供应链完整性加固手法并能在本仓库中直接复现全部验证命令。评审背景四路评审、两个硬阻塞与四个安全项这次安全评审针对 PR #6858 的 head 提交5e530b4e2885a9a38d0fe108f27fa5a055b37142展开完整评审结论记录在 audit-findings.md 中。评审分为五条 laneLane结论阻塞项目标与约束Goal and constraintsFAIL生成式 bundle 冲突、缺当前 head CI、Windows 证据不可审计代码质量Code qualityFAIL生成式 bundle 冲突源码改动本身正确安全与进程安全Security and process safetyPASS无安全阻塞实操 QAHands-on QAFAIL缺当前 head CI生产 RPC 路由证据失效仓库与历史上下文FAIL生成式 bundle 冲突、缺当前 head CI评审同时确认了五个评审阻塞项机械性不可合并、缺当前 head CI 运行、Windows 证据不可审计、task-rpc-e2e.mjs报告execution_mode: process未到达 RPC runner、PR 正文链接过期并明确拒绝了两个非阻塞项spawnProcess为测试桩扩展公开重导出类型属既有仓库 seam 模式、其他组件的 Windows pipe spawn 属后续范围而非本 PR 回归。真正进入安全阻塞清单的是 security-blockers.md 中记录的四项每项都遵循严格的 RED→GREEN 证据闭环先给出失败复现命令与失败断言再给出修复后的生产改动、验证命令与通过结果。阻塞项一RPC 子进程树的存活问题进程组级终止REDTERM-ignoring 后代进程存活原始缺陷通过一条命令复现bun test packages/senpi-task/src/runners/rpc/terminate.test.ts观察结果直接 RPC 子进程在升级escalation后已退出忽略 SIGTERM 的后代进程仍然存活断言以Expected: false、Received: true失败套件结果 3 通过、1 失败。测试夹具会启动一个真实子进程由它再启动一个长生命周期后代进程全程不经过 shell——这意味着问题不在 shell 包装层而在进程树的终止策略本身。GREEN进程组拥有者 SIGTERM/SIGKILL 有界升级修复后的生产改动对应 terminate.tsPOSIX 下 RPC 根进程以拥有进程组owned process group的方式启动终止时先对进程组发送 SIGTERM再按有界延迟升级为 SIGKILLWindows 下改用taskkill.exe /PID pid /T /F且shell: false避免经过 shell 转发引入注入面测试通过ps -o stat区分仍在执行的进程与已终止的 POSIX 僵尸进程不依赖 sleep 等待。从源码看terminate.ts 的terminateRpcChild是 RPC 子进程终止的单一写入点模块注释明确声明这是唯一允许向 RPC 子进程发送信号的模块。其核心逻辑在 terminatePosixProcessGroup先通过process.kill(-pid, 0)探测进程组是否存在processGroupExistsESRCH 视为不存在进程组存在时对-pid发送 SIGTERMwaitForExitOrDelay用Promise.race在子进程退出与默认 5 秒DEFAULT_SIGKILL_DELAY_MS 5_000升级延迟之间竞争延迟到期后进程组仍存在则升级发送 SIGKILL并以 2 秒为上限、10 毫秒间隔轮询等待PROCESS_EXIT_OBSERVATION_TIMEOUT_MS/PROCESS_EXIT_OBSERVATION_INTERVAL_MS。对非组领导者调用方terminateDirectChild 提供直系子进程的回退路径同样的 SIGTERM→有界延迟→SIGKILL 升级。Windows 分支 terminateWindowsProcessTree 用shell: false直接 spawntaskkill.exe并在任务结束后仍校验子进程是否退出、必要时补发 SIGKILL。对应测试 terminate.test.ts 覆盖了五类场景配合的子进程被 SIGTERM 优雅终止、TERM-ignoring 子进程在预算内升级为 SIGKILL、非组领导者子进程仍可终止、已退出子进程重复终止不抛错、以及TERM-ignoring 后代进程随整棵树退出通过process-tree.mjs夹具读取后代 PID 后轮询验证。验证命令与结果bun test packages/senpi-task/src/runners/rpc/terminate.test.ts bun test packages/senpi-task/src/runners bun run --cwd packages/senpi-task typecheck观察结果终止套件 4 通过 0 失败聚焦的 runner/终止套件 15 通过 0 失败包类型检查 exit 0。阻塞项二可伪造的生成式 bundle 新鲜度标记产物完整性双校验RED注入 JS 主体后标记仍然匹配复现命令bun test packages/omo-senpi/plugin/scripts/build-artifact.test.mjs观察结果向产物中注入一段 JavaScript 主体后原本的 source digest 仍被保留可编辑主体的 digest 被重新计算artifactsMatch()返回true断言以Expected: false、Received: true失败。这说明旧校验只验证了标记中的 digest 与当前主体一致而没有验证当前主体与新鲜生成的主体字节一致——攻击者可以在篡改主体后顺手重算并覆写标记使校验形同虚设。GREEN双标记 字节一致性 固定压缩器版本修复后的生产改动对应 build-artifact.mjs门禁同时校验两个产物标记与其对应主体当前主体 digest 与新鲜生成的主体 digest 必须一致当前主体与新鲜生成的主体必须字节级一致byte-identicalBun 标识符混淆identifier mangling被替换为可复现的语法/空白压缩 固定terser5.44.0标识符混淆压缩器版本被纳入构建设置 digest压缩器一旦变动标记立即失效。从源码看artifactsMatch 的判定链是current.sourceDigest expected.sourceDigest且current.bodyDigest digest(current.body)、expected.bodyDigest digest(expected.body)最后要求两者 digest 相等且主体字节相等。标记格式为// omo:sourceDigest:bodyDigest追加在产物头部shebang 保留在字节 0标记位于其下一行digest 覆盖含 shebang 的整个主体见 attachBuildMarker。digestBuildSources对 metafile 中所有输入文件按排序后的 key 逐个做 sha256 累加并把构建脚本自身与build-artifact.mjs也纳入摘要。可复现性保证落在 build-extension.mjs 的构建参数上minifySyntax: true、minifyWhitespace: true、minifyIdentifiers: false、secondaryMinifier: terser5.44.0CLI 形态对应--minify-syntax --minify-whitespace加--metafile随后minifyBundle再做一次 terser 压缩。验证命令与结果bun test packages/omo-senpi/plugin/scripts/build-artifact.test.mjs npm exec --yes --packagebun1.3.12 -- bash -c node packages/omo-senpi/plugin/scripts/build-extension.mjs --check bun test packages/omo-senpi/src/bundle-size.test.ts观察结果伪造回归测试 1 通过 0 失败跨进程字节一致性检查 exit 0omo.js产物 764,648 字节低于 1,050,000 字节预算bundle 体积与产物完整性门禁 2 通过 0 失败。关于体积预算的演进背景bundle-size.test.ts 的注释完整记录了从 700,000 逐步上调到 1,050,000 的历史每次上调都对应明确的功能增量如 memory 组件、lett-memory-parity-port、native-telemetry 波次且始终遵守不留意外膨胀空间、不引入新第三方依赖的纪律——这是本仓库对单文件非拆分 bundle 拓扑的坚持压缩是文件内语义保持变换而代码拆分会产生兄弟 chunk需要改动加载器拓扑因此被排除。阻塞项三相对可执行路径替换路径规范化防劫持RED相对路径被任务控制的工作目录重解析复现命令bun test packages/senpi-task/src/runners/rpc/spawn.test.ts观察结果相对形式的SENPI_BIN只相对父进程校验后原样返回相对形式的PATH条目同样返回相对可执行路径两条回归断言均失败因为后续任务可控的cwd可能把这些路径解析到完全不同的文件。风险本质RPC 子进程的cwd由任务 spec 提供buildRpcSpawn中cwd: spec.cwd若可执行路径保持相对任务即可通过切换工作目录把你以为的 senpi替换成任务放置的任意可执行文件形成任意代码执行。GREEN全部候选路径绝对化 符号链接规范化 文件类型校验修复后的生产改动对应 senpi-launcher.ts 与 spawn.ts显式覆盖项SENPI_BIN、兄弟候选、PATH 候选一律解析为绝对路径realpathSync.native规范化符号链接与平台路径别名statSync(...).isFile()在 spawn 前拒绝目录与非文件候选。从源码看canonicalExecutable 组合了realpathSync.native(resolve(candidate))与statSync(canonical).isFile()两道闸门任何一步抛错即返回 null。resolveSenpiExecutable的候选优先级为显式SENPI_BIN覆盖即使其包版本与引擎不同也直接采用→ 编译引擎运行时自身isCompiledEngine即 omo 单文件二进制内嵌引擎spawnprocess.execPath即得到同版本同资产的后代→ Bun 二进制旁边的兄弟 senpi → PATH 扫描。兄弟与 PATH 候选还会经过引擎版本一致性校验passesEngineParity候选的code-yeongyu/senpimanifest 版本与运行中引擎版本不符时被跳过并告警无 manifest 可读的候选则保留。配套的 Windows 细节在 normalizeSenpiLauncher非.exe后缀候选被识别为 npm shim回溯其相邻node_modules/code-yeongyu/senpi/dist/cli.js而 isRunningCompiledEngine 防止把无扩展名的编译引擎自身误判为 shim 而丢弃唯一保证版本匹配的候选。验证命令与结果观察结果可执行解析套件 23 通过 0 失败两类相对路径场景均返回规范化绝对路径senpi-task 类型检查与 LSP 诊断干净。验证覆盖了SENPI_BIN缺失路径不静默回退、空 PATH 不命中、bun 兄弟缺失时透传回退、版本不匹配被拒绝、stale 与匹配 PATH 候选并存时匹配者胜出、以及显式覆盖优先于版本校验等分支。阻塞项四进程包含边界的诚实声明修复后的terminateRpcChild契约在 terminate.ts 与证据文档中有明确边界声明POSIX回收其拥有的 RPC 进程组Windows通过taskkill /T /F回收可发现的进程树非组领导者调用方直系子进程回退真实 TERM-ignoring 子进程与后代进程夹具无需 sleep 即可通过。文档同时明确强调该 runner 不是操作系统沙箱。已被信任可以访问 Agent 文件系统、网络与凭据的代码可以刻意守护进程化daemonize到新会话或制造不可逆的外部副作用阻止这些需要独立的沙箱/容器架构不属于本 PR 子进程生命周期契约的承诺范围。平台 QA 要求通过证明拥有的 RPC 树退出、且无记录的子 PID 残留来满足——这个边界声明本身就是安全评审的重要产物它防止后续把进程终止误当作沙箱隔离来使用。全量回归修复后的 Senpi 完整门禁所有安全修复落地后运行全量门禁bun run test:senpi观察结果1,715 通过1 个有意的 Windows-only 生产驱动跳过0 失败1,716 个测试共 4,844 条断言耗时 148.41 秒。文档同时确认全程不保留任何 provider token、凭据体、授权头、私钥或原始环境转储。复现与验证命令速查目的命令进程树终止回归bun test packages/senpi-task/src/runners/rpc/terminate.test.tsRPC runner 全量bun test packages/senpi-task/src/runners可执行路径解析回归bun test packages/senpi-task/src/runners/rpc/spawn.test.tssenpi-task 类型检查bun run --cwd packages/senpi-task typecheck产物伪造回归bun test packages/omo-senpi/plugin/scripts/build-artifact.test.mjs跨进程字节一致性检查npm exec --yes --packagebun1.3.12 -- bash -c node packages/omo-senpi/plugin/scripts/build-extension.mjs --checkbundle 体积与完整性门禁bun test packages/omo-senpi/src/bundle-size.test.tsSenpi 全量门禁bun run test:senpi总结四条可复用的安全加固经验进程树终止要按进程组治理POSIX 用process.kill(-pid, ...)面向进程组、SIGTERM 后按有界延迟升级 SIGKILLWindows 用taskkill /T /F且shell: false并把信号发送收敛到单一模块杜绝多方抢发。产物完整性校验要防自洽伪造任何标记与主体一致的校验都必须同时叠加当前主体与新鲜构建字节一致的校验digest 要覆盖含 shebang 的完整主体压缩器版本要钉死并纳入构建摘要保证可复现。可执行路径在 spawn 前必须绝对化realpathSync.nativestatSync.isFile()双闸门杜绝任务可控cwd造成的相对路径劫持候选来源覆盖项/兄弟/PATH/引擎自身要有明确优先级与版本一致性过滤。安全边界要诚实声明进程终止不是沙箱二者不可混用明确契约范围既能防止误用也是评审可审计性的基础。上述全部实现与测试均可直接在本仓库中检视与复现进程终止见 terminate.ts 与 terminate.test.ts可执行路径解析见 senpi-launcher.ts 与 spawn.test.ts产物完整性见 build-artifact.mjs、build-extension.mjs 与 build-artifact.test.mjs完整评审背景见 audit-findings.md。【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Unity游戏接入穿山甲广告SDK完整指南与避坑实录

Unity游戏接入穿山甲广告SDK完整指南与避坑实录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/23 2:54:52 阅读更多 →
Exchange Server 2016部署与DAG高可用实战指南

Exchange Server 2016部署与DAG高可用实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 12:59:39 阅读更多 →
pyasc 队列状态查询:TQue.vacant_in_que 接口原理与实战(附与 has_idle_buffer 等状态接口对比)

pyasc 队列状态查询:TQue.vacant_in_que 接口原理与实战(附与 has_idle_buffer 等状态接口对比)

pyasc 队列状态查询:TQue.vacant_in_que 接口原理与实战(附与 has_idle_buffer 等状态接口对比) 【免费下载链接】pyasc 本项目为Python用户提供算子编程接口,支持在昇腾AI处理器上加速计算,接口与Ascend C一一对应并遵…

2026/9/21 12:29:17 阅读更多 →

最新新闻

SSM框架实战:高校学报管理系统设计与实现解析

SSM框架实战:高校学报管理系统设计与实现解析

1. 项目概述与选型背景第一次看到“SSM商丘工学院学报管理系统”这个标题时,我其实挺有感触的。高校内部的业务管理系统,尤其是学报管理这种带有明确流程特征的场景,一直是SSM框架最典型的应用土壤。Spring、SpringMVC、MyBatis这三位老搭档组…

2026/9/23 3:58:31 阅读更多 →
AI日报背后的工程实践:Agent架构、密钥安全与LLM输出稳定性

AI日报背后的工程实践:Agent架构、密钥安全与LLM输出稳定性

1. 从一份日报标题说起:AI 日报到底在记录什么看到"AI 日报 2026-09-18"这个标题,很多人第一反应是"这不就是个新闻汇总吗"。但如果你真的每天跟踪 AI 领域的动态,就会知道一份有价值的日报远不止是链接堆砌。它本质上是…

2026/9/23 3:58:31 阅读更多 →
为长时运行的 AI 编码代理设计持久化 Harness:OpenAI 风格仓库模板 AGENTS.md 深度解析

为长时运行的 AI 编码代理设计持久化 Harness:OpenAI 风格仓库模板 AGENTS.md 深度解析

为长时运行的 AI 编码代理设计持久化 Harness:OpenAI 风格仓库模板 AGENTS.md 深度解析 【免费下载链接】learn-harness-engineering Harness engineering beginner tutorial, from 0 to 1 项目地址: https://gitcode.com/gh_mirrors/le/learn-harness-engineerin…

2026/9/23 3:58:31 阅读更多 →
穿越火线怎么调烟雾头图解原理:5分钟吃透底层逻辑

穿越火线怎么调烟雾头图解原理:5分钟吃透底层逻辑

穿越火线怎么调烟雾头图解原理:5分钟吃透底层逻辑 CF手游里的烟雾弹为啥总是飘歪?官方教程只告诉你“按住技能键”,却从不解释背后的物理引擎。这种 官方文档太长抓不住重点 的体验,让无数玩家在实战中只能靠玄学猜。今天咱们不背口诀,直接上…

2026/9/23 3:58:31 阅读更多 →
PlantUML 内部 DITAA 引擎解析:`ascii2image` 核心包与 ASCII 艺术到图像的转换管线

PlantUML 内部 DITAA 引擎解析:`ascii2image` 核心包与 ASCII 艺术到图像的转换管线

开发工具文档 【免费下载链接】plantuml Generate diagrams from textual description 项目地址: https://gitcode.com/gh_mirrors/pl/plantuml 点击查看 免费下载 本篇技术指南聚焦于 PlantUML 仓库中内置的 ditaa(Diagrams Through ASCII Art&#xf…

2026/9/23 3:58:30 阅读更多 →
代码世界模型:从编码智能体到理解世界的数字大脑

代码世界模型:从编码智能体到理解世界的数字大脑

直接说结论:代码世界模型这个提法,乍一听很像概念炒作,但你把它拆开看,其实是把“让大模型通过写代码来理解世界”这个路线推到极致的一种尝试。我最近半年一直在折腾编码智能体相关的项目,从最早的代码补全&#xff0…

2026/9/23 3:57:30 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/22 4:32:41 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/22 4:38:57 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →