datamodel-code-generator:一行weakimport,为什么能写到目录之外"

admin 2026-11-01 02:00:55 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

datamodel-code-generator:一行 weak import,为什么能写到目录之外

原创

云梦DC
云梦DC

云梦安全

2026年10月29日 11:21
河南

去阅读

2026 年 10 月披露的 CVE-2026-107377(GHSA-77xj-x4rm-935c,CVSS 7.5)出在 datamodel-code-generator 的 Protobuf 输入处理。这个工具常被放进代码生成流水线,把 JSON Schema、OpenAPI、XSD 或 .proto 转成 Python 模型。输入经常来自上游仓库、URL 或第三方交付物,未必都可信。

本地用 0.80.0 跑一份带恶意 import weak 的 schema,protoc 最后报错退出了,但目录外的文件已经写出来,另一个已有文件也被覆盖。换到 0.81.0,生成器在写入前抛出 Invalid Protocol Buffers weak import path,磁盘没有变化。

漏洞速览

项目 内容
漏洞编号 CVE-2026-107377 / GHSA-77xj-x4rm-935c
影响组件 datamodel-code-generator 0.59.0–0.80.0
修复版本 0.81.0
漏洞类型 路径穿越导致任意文件写入(CWE-22)
危害等级 CVSS 7.5 High
触发前提 对不可信 .proto 执行 protobuf 代码生成

weak import 的补文件逻辑

Protobuf 的 import weak 表示依赖可以缺失。为了让 protoc 继续编译,生成器会在临时目录里为每个 weak import 补一个空壳文件,里面只有一行 syntax 声明,再把这个目录加入 include path。

问题在文件名直接取自 schema:

WEAK_IMPORT_PATTERN = re.compile(r'^\\s*import\\s+weak\\s+”([^”]+)”\\s*;', re.MULTILINE) stub = self.weak_import_dir / import_pathstub.parent.mkdir(parents=True, exist_ok=True)stub.write_text(syntax, encoding=self.parser.encoding)

正则的捕获组没有限制字符,import\_path 可以包含 /、..,也可以是绝对路径。pathlib 的 / 运算符在这里有两个关键行为:右操作数是绝对路径时,左边整个被丢掉;.. 不会被自动拦下或规范化。mkdir(parents=True) 还会把中间目录一起建出来。

于是写入位置可以落到临时目录之外。比如:

import weak ”/home/user/.config/x”;import weak ”../../victim.txt”;

第一条拼出绝对路径,第二条从临时目录往上爬两级。

检查和写入用的不是同一个位置

写文件之前,代码确实做了一次存在性检查:

if any((include_path / import_path).exists() for include_path in include_paths):    continue

但 include\_paths 是“输入文件所在目录 + 临时目录”等候选路径,真正写入用的是 weak\_import\_dir / import\_path。检查是按其中某个目录算的,写入是按临时目录算的,两边并不一定指向同一个文件。

绝对路径的表现比较特殊。include\_path / \"/abs/x\" 无论左边是什么,结果都是 /abs/x,所以目标已存在时会被跳过。它更适合新建文件,不容易覆盖现有文件。

相对路径 ../../victim.txt 就不一样了。检查时从输入目录往上爬,写入时从临时目录往上爬,两个路径可以指向不同文件。攻击者只要让检查目标不存在、写入目标存在,就能绕过检查完成覆盖。

这里的根因是路径基准不一致,不涉及并发时序。校验和真正落地如果不用同一个已经解析、规范化的路径,检查通过并不能说明写入安全。

0.80.0 和 0.81.0 的磁盘结果

实验准备了一份 evil.proto,同时放绝对路径和 ../../victim.txt 两条 weak import。目标目录里先放 victim.txt,内容为 ORIGINAL BUILD CONFIG。

0.80.0 执行后,protoc 报了三条错:文件不存在、虚拟路径不允许 ..、import 无法解析,进程以非零码退出。但在这之前,abs\_pwn.txt 已经被创建,内容是 syntax = \"proto3\";;victim.txt 也被同一行内容覆盖。

这一点在排查时容易漏掉。构建失败只说明后续步骤没走通,前面的文件系统副作用已经发生了。看 CI 日志时,不能因为最后一条是 protoc 报错就认定没有写入。

0.81.0 在检查阶段抛 Invalid Protocol Buffers weak import path。abs\_pwn.txt 不存在,victim.txt 还是原来的内容。

影响边界要说清楚

写入内容不可控,只有一行 syntax = \"proto2\"; 或 syntax = \"proto3\";,公告也没有演示出直接代码执行。把它直接说成“任意文件写入导致 RCE”不准确。

但完整性影响仍然存在。构建关键文件可能被覆盖,比如 init.py、锁文件、入口脚本、CI 配置;目录树可以被任意创建,文件也能落到被监听或自动加载的位置。生成器进程如果有制品仓库凭据、部署密钥或云平台令牌,攻击者还可以把一次构建破坏拆成后续几步。

触发条件也不算苛刻。流水线只要处理一个第三方 .proto,或者通过 --url 拉取远程 schema,就会走到这段逻辑。代码生成又常跑在构建节点上,权限通常比普通业务容器高。

0.81.0 的修复顺序

0.81.0 会把临时目录和候选 stub 路径都做 resolve(),再判断候选路径是否仍位于临时目录内。不在范围内就抛 SchemaParseError。这个判断放在创建父目录、写文件之前,输入准备失败时临时目录也会清理。

路径校验的顺序很关键。先解析、规范化,再判断包含关系,最后才创建和写入。反过来先建目录、先打开文件,再补检查,副作用已经留下了。

需要覆盖的输入形态至少有三类:绝对路径、带 .. 的相对路径,以及符号链接。前两类是这次公告的重点;符号链接要在 resolve() 之后判断目标位置,否则链接指向的仍可能是目录外。

    日本SonyNetworkCommunications超258万条客户记录被泄露" 网络安全文章

    日本SonyNetworkCommunications超258万条客户记录被泄露"

    日本索尼网络通信公司披露数据泄露事件,超258万条客户记录遭未授权访问,涉及So-net会员及plala客户数据,含姓名、邮箱、用户ID等,另有54,401个邮箱及密码泄露,16条银行账户记录受影响。索尼已重置受影响账户密码,向日本个人信息保护委员会报告,并提醒用户警惕可疑通信。建议受影响客户通过官方渠道重置密码并防范钓鱼攻击。
    网安学生如何0成本拥有自己的服务器" 网络安全文章

    网安学生如何0成本拥有自己的服务器"

    本文分享网安学生如何零成本获取阿里云服务器,通过学生认证领取300元优惠券,用于购买一年期服务器或API额度,步骤包括访问阿里云官网、搜索学生专属权益、验证学生身份并申领优惠券,最后选择284元套餐消费。文章属于羊毛分享类内容,具有推广性质,操作建议明确但深度有限。
    PHP双高危漏洞来袭:全场景防护规则同步升级,手把手做好补丁前安全兜底" 网络安全文章

    PHP双高危漏洞来袭:全场景防护规则同步升级,手把手做好补丁前安全兜底"

    PHP官方发布两枚高危远程代码执行漏洞,CVSS评分9.2,影响PHP8.0至8.3等多个主流版本,公开POC已扩散,利用门槛极低。文章建议先排查资产版本,升级至8.1.32、8.2.26、8.3.16及以上修复版本,补丁落地前通过更新WAF、IPS等8类安全产品防护规则兜底,并给出查版本、升PHP、上规则、验防护四步闭环操作指南。
    评论:0   参与:  0