Colibrì如何防御恶意模型文件?信任边界设计与内存安全修复深度剖析
【免费下载链接】colibriRun frontier MoE models on hardware you already own — pure C, zero deps, experts streamed from disk. Tiny engine, immense model. 🐦项目地址: https://gitcode.com/gh_mirrors/colibri3/colibri
Colibrì 是一个用纯 C 编写、零依赖的 MoE(混合专家)推理引擎,能把 744B 到 2.8T 参数的前沿模型跑在你自己的电脑上,专家权重按需从磁盘流式读取。但"从本地加载别人提供的模型文件"这件事本身就带风险:模型权重可能来自不受信的镜像站,config.json可能被恶意篡改。本文拆解 Colibrì 如何把恶意模型文件当作攻击者输入来防御——它的信任边界设计、"宁可拒绝也不猜测"的加载纪律,以及 v1.6.2 安全版本修复的 6 个内存安全漏洞。
🛡️ 为什么模型文件是最大的信任边界?
多数推理软件默认"本地模型是可信的"。Colibrì 恰恰相反,它在 CHANGELOG.md 中把威胁模型写得明明白白:
Threat model: model files come from mirrors that are not trusted.(威胁模型:模型文件来自不受信任的镜像站。)
对一个需要下载 372 GB 权重、还要解析config.json、safetensors 分片头、甚至服务端 stdin 的引擎来说,攻击者可控的输入有四个入口:
| 入口 | 攻击面 | 典型风险 |
|---|---|---|
| 模型权重分片 | 伪造的张量字节数、形状、格式 | 堆溢出、越界读写 |
config.json | 声明任意维度的 JSON | 加载期 OOM、空指针解引用 |
| safetensors 分片头 | 伪造 header 长度 | 巨型 malloc |
| 服务端 stdin / HTTP 请求 | 超长 token id、超大请求体 | 越界写、信息泄露 |
Colibrì 的总原则是:在信任边界处验证,对畸形输入大声拒绝(fail loud),对合法模型零行为变化。下面按数据流从"字节"到"token"逐层看它怎么做到。
第一道关口:容器头部的"门卫"——safetensors 头大小封顶
模型分片文件以 safetensors 格式组织,每个分片开头有一段 JSON 头,声明里面有哪些张量。恶意文件可以在头里声明一个天文数字的hlen,让引擎在读取前就分配巨型内存。
c/st.h 的处理非常直接:
- 定义
ST_MAX_HEADER上限(512 MB)——真实头只有 KB 到 MB 级,超出即拒绝; - 多分片场景下,跨分片的重复张量名不再静默"取其一",而是直接拒绝(#1106,v1.7.0 落地),防止伪造头把名字"劫持"到任意分片上。
另外,双 SSD 镜像分片只有在文件大小和 safetensors 头逐字节一致时才会被接受为副本(见 c/st.h 的st_mirror_add注释),不一致的文件自动留在主盘——副本从来不会"半可信"地混入计算路径。
第二道关口:config.json 的有界读取(SEC-9)
config.json决定模型的全部维度:隐藏层大小、层数、专家数、词表……它同样来自不受信目录。修复前的写法是ftell → malloc无上限读取:一个几 GB 的恶意文件就能在加载时打爆内存(OOM),或让malloc失败后的b[got]=0变成空指针解引用。
c/colibri.c 中的cfg_slurp打了三个补丁,代码注释标为SEC-9:
- 大小封顶:超过 256 MB 直接拒绝(真实 config 只有 KB 级);
- malloc 返回 NULL 检查:失败即返回,不再裸奔解引用;
- 要求完整读满:短读(peer 中途断开)视为失败。
其他引擎家族同样执行了这条纪律,例如 c/olmoe.c 对config.json做同样的 256 MB 上限校验,且注释强调"缺失的键曾经是空指针解引用"。
第三道关口:量化格式"拒绝而非猜测"
这是 Colibrì 信任边界里最硬核的一层。量化权重的字节布局(int8 / int4 / int2 / FP8……)在磁盘上只有字节数,格式要引擎自己推断。伪造的容器可以让字节数恰好撞出另一种格式的"签名",诱导引擎用错误方式解码——轻则输出乱码,重则越界读。
c/colibri.c 的裁决规则只有一条:字节数对不上任何一种合法布局 → 打印明确原因并exit(1),注释里反复出现 "refusing (untrusted container)"(拒绝,不受信容器)。
更妙的是它对"字节数巧合"的处理。代码注释(c/colibri.c)把一处真实存在的碰撞称为"设计地雷"(THE DESIGN LANDMINE):GLM-5.2 自己的o_proj张量,其 int8 按行布局的字节数与 FP8 分块布局的签名完全相同。维护者没有一刀切拒绝(那会拒绝一个合法模型),而是建立了"信任 → 验证 → 拒绝"三级路径:
- 有元数据戳(stamp)且指向唯一候选→ 按戳解析;
- 戳指向无法消歧的格式→ 按名拒绝;
- 无戳且形状模糊→ 只解析为"已落盘、可解码"的既有格式,因为写入侧工具已保证不会在该形状下产出歧义容器。
Kimi K3 引擎执行同样纪律:c/kimi_k3.c 对 U8 张量先核对 int8 与 int4-g64 两种布局的精确字节数与 scale 数组规模,两者都不匹配就拒绝加载。
🧨 v1.6.2 安全版本:6 个内存安全漏洞的修复清单
2026-08-14 发布的 v1.6.2 是一个纯安全版本:CHANGELOG.md 记录了六个私下报告的内存安全问题,全部可从攻击者可控输入触达(恶意模型文件 /config.json,或 kimi_k3 的 SERVE stdin)。修复方式统一为"信任边界处验证,合法输入零行为变化":
| 安全公告(GHSA) | 位置 | 类型 | 边界修复 |
|---|---|---|---|
| GHSA-gf38-c8fx-ppvv | kimi_k3 SERVE stdin | 越界写 | 输入 token 序列在解码前做长度边界校验 |
| GHSA-2qrj-xjmh-mv74 | c/json.h | 越界读 | JSON 解析器按真实缓冲区长度约束 |
| GHSA-w696-h9p7-6rgc | inkling 音频路径 | 越界 | 多模态负载按声明形状复核 |
| GHSA-7654-r78q-vc3r | deepseek_v4 索引器 | 越界读/写 | 索引张量形状在批投影前校验 |
| 另两则同类 | 模型加载路径 | 越界类 | 全部落在容器解析边界 |
配合两处更底层的防线:
- SEC-5:c/colibri.c 中,越界 token id 不会越界读嵌入表,而是填零行返回——"越界 token → 零行,永不越界";
- SEC-9 之外的形状防护:v1.1.0 的 #413 修复让量化布局必须与磁盘字节数互相验证,形状乘积溢出被拒绝,olmoe 的 dtype-3 路径不再信任伪造的
nbytes(那曾是一个堆溢出)。
第四道关口:HTTP 服务端的"失败即关闭"
coli serve/coli web暴露一个 OpenAI 兼容 API,这是引擎唯一的网络面。c/openai_server.py 用SEC-6/7/8三个标记实现了纵深防御:
- SEC-6(失败即关闭):非环回地址绑定而未配置 API key时,引擎拒绝启动(openai_server.py)——未认证的引擎绝不裸露在网络上;
- SEC-7(DNS 重绑定防御):_check_host 校验 Host 头。恶意网页可以把域名解析到
127.0.0.1从而驱动你的本地服务,这里把 Host 钉死在环回/绑定地址上,其余一律 403; - SEC-8(信息泄露收敛):路由遥测等端点未认证一律隐藏(openai_server.py),且认证比较使用
hmac.compare_digest恒定时间比对防时序侧信道(openai_server.py); - 请求体封顶:
read_json强制Content-Length在 1 到MAX_BODY之间,非法直接 400(openai_server.py); - 静态资源防路径穿越:仪表盘文件服务用
resolve()+relative_to(base)双重校验,../出不了web/dist(openai_server.py)。
🔬 工程层面:用 CI 和校验和兜底
信任边界不是只靠"写对代码",还要防回归:
- Sanitizer 常设:c/Makefile 提供
test-asan目标,用-fsanitize=address,undefined -fno-sanitize-recover=all编译关键解码路径——任何 ASan/UBSan 报告都算失败; - 二进制可验证:每次 release 附带
SHA256SUMS.txt,下载的引擎能与 CI 从 tag 源码构建的产物逐字节核对(CHANGELOG.md); - 本地历史文件也分级:
.coli_usage(路由热度历史)只有用户亲手敲路径时才被trusted=1加载,自动发现的同名文件按不受信处理(c/colibri.c)——连"自己目录里的旧文件"都不默认信任。
给普通用户的三条建议
- 只从官方 release 下载引擎,并用
SHA256SUMS.txt核对,避免"引擎本身被投毒"; - 模型权重下载后核对大小(如 GLM-5.2 容器约 372 GB);即便拿到损坏或伪造的容器,Colibrì 也会在加载阶段拒绝并给出具体原因,而不是带着错误格式继续跑;
- 局域网共享服务时务必设置 API key,引擎会在无 key 的公网绑定下直接拒绝启动——这是设计保证,不是文档建议。
结语:把"本地文件"当"网络输入"对待
Colibrì 给整个本地推理生态树立了一个少见的设计标杆:用户机器上的一切字节——权重、配置、镜像分片、历史缓存、HTTP 请求——默认来自不受信来源。它不靠加密或签名兜底(模型太大,签名不现实),而是靠一条可审计的工程纪律:每个信任边界处验证、歧义即拒绝、拒绝必须说明原因。对于跑在个人硬件上的 744B 参数巨兽,这比任何华丽的性能数字都更接近"可托付"。🐦
【免费下载链接】colibriRun frontier MoE models on hardware you already own — pure C, zero deps, experts streamed from disk. Tiny engine, immense model. 🐦项目地址: https://gitcode.com/gh_mirrors/colibri3/colibri
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考