TL;DR
2026-08-27 公开的 CVE-2026-81934 是 Redis 自带 TLS 终止(tls-port)场景下的 use-after-free:tlsProcessPendingData() 用迭代器遍历 pending-data 链表时,同一循环里命令处理把当前节点释放了,迭代器随后读取已释放内存------轻则崩溃,重则被构造成远程代码执行。
- 触发条件:Redis 自己终止 TLS(不是反代/负载均衡后面)+ 攻击者能到达 TLS 端口;
- 评分争议 :NVD 初评 9.8(Critical) ,Redis 官方自评 7.5(High,CVSS v4.0)------争议核心是可利用性前提(是否需认证、运行条件多苛刻);
- 修复版本:Redis OSS 8.10.1 / 8.8.2 / 8.6.6 / 8.4.6 / 8.2.9 / 7.4.11 / 7.2.16 / 6.2.24;Redis Software 8.2.0-46 / 8.0.20-96 / 7.22.2-179 / 7.8.6-303;
- 一句话判断 :跑裸
tls-port且端口可达 → 尽快升级;TLS 终止在代理层、Redis 只收明文内网流量 → 本漏洞不达,但版本照升。
官方公告说了什么
Redis 官方 2026-08-28 发布安全公告(Security Advisory: CVE-2026-81934),核心信息:
| 项 | 内容 |
|---|---|
| 漏洞类型 | use-after-free(UAF) |
| 触发函数 | tlsProcessPendingData()------TLS pending-data 处理 |
| 官方定性 | 「在特定条件下,已认证攻击者可触发并可能执行远程代码」 |
| 官方评分 | 7.5(High),CVSS:4.0/AV:A/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
| NVD 初评 | 9.8(Critical)------官方已联系评分机构要求复核 |
| 在野利用 | 截至 2026-08-27 无已知主动利用 |
| 公开 PoC | 第三方称已有公开 PoC(官方公告未确认) |
公告里特别强调的加固项:限制 Redis 网络访问到可信客户端、强制强认证与最小权限 ACL、移除不必要的 CLIENT KILL / Lua 脚本 / Pub/Sub 及相关 key 权限、绝不对公网直接暴露 Redis。
漏洞机理:迭代器与释放的竞速
pending-data 链表是什么
Redis 用 OpenSSL 做 TLS 终止时,解密后的数据先进入内存缓冲。tlsProcessPendingData() 的角色是:把 TLS 连接上待处理的解密数据逐条取出来,交给 Redis 的命令处理器执行。它的内部用一个链表保存这些 pending 数据块,并用迭代器逐节点遍历。
UAF 怎么发生
经典 UAF 三步:
- 迭代器持有当前节点的引用,准备读取/处理这个节点的数据;
- 在遍历循环的某个间隙,命令处理逻辑执行了释放操作------把迭代器还没遍历完的节点 free 掉(pending-data 链表的节点可能因命令处理、连接关闭、超时清理等路径被释放);
- 迭代器继续前进,读取已释放的内存------此时该内存可能已被复用(堆上重新分配给了别的对象),读到的是「幽灵数据」,或者直接触发崩溃。
用伪代码描述(基于公开分析的机理还原,非逐行源码):
c
// tlsProcessPendingData 的简化示意(非逐行源码)
static void tlsProcessPendingData(connection *conn) {
listIter li;
listNode *node;
// ① 迭代器开始遍历 pending 链表
listRewind(conn->pending, &li);
while ((node = listNext(&li)) != NULL) {
// ② 取出当前节点数据交给命令处理器
char *buf = listNodeValue(node);
int n = processInputBuffer(conn, buf, len); // ← 处理命令
// ③ 命令处理过程中可能释放 conn 的 pending 节点
// (连接关闭/清理/错误路径触发 free)
// ④ 迭代器继续 listNext() 时 node 已是悬空指针 → UAF
if (n == C_ERR) break;
}
}
关键点:释放发生在遍历循环中途,迭代器没有机会感知。这不是缓冲区溢出、不是注入,是典型的内存生命周期管理错误------「引用先于释放失效」。
为什么必须 Redis 自己终止 TLS
tlsProcessPendingData() 这条代码路径只在 Redis 内置 TLS 终止时存在。如果你的架构是:
scss
客户端 --TLS--> Nginx/HAProxy/云LB --明文--> Redis(port 6379)
TLS 在代理层就终结了,Redis 收到的全是明文内网流量,tls-port 没开,tlsProcessPendingData() 永远不会执行------本漏洞不达你。只有:
scss
客户端 --TLS--> Redis(tls-port 6380,自己持证书)
这种「Redis 裸奔 TLS」的部署才在攻击面内。
UAF 的现实后果:从崩溃到 RCE 的谱系
UAF 的杀伤力取决于「释放后、读取前,那块内存被什么复用」:
| 复用情况 | 后果 | 触发难度 |
|---|---|---|
| 内存尚未被重新分配 | 读到旧数据,行为异常但不一定崩 | 低 |
| 被分配给了其他对象 | 读到「幽灵对象」的字段,逻辑错乱或崩溃 | 中 |
| 被攻击者精心布局的对象占据 | 可被塑造成任意读写原语 → 提权/RCE | 高(需堆布局技巧) |
Redis 官方不声称有完整的武器化 RCE 链,但也不排除------公开 PoC 把「理论上限」变成了「实际已有人在做」。对运维来说,不用赌它能不能 RCE:崩溃本身在 TLS 服务上就是拒绝服务,UAF 崩溃 + 重连风暴会连带打挂依赖 Redis 的上游应用。
评分争议:9.8 还是 7.5
同一个漏洞两个分数,不是笔误,是两套评估逻辑:
| 维度 | NVD 初评 9.8 | Redis 官方 7.5 |
|---|---|---|
| 依据标准 | 倾向 CVSS v3.1 | CVSS v4.0 |
| 攻击前提假设 | 低复杂度、无需权限 | 已认证访问 + 协调的 TLS 会话 + 精确运行条件 + 目标特定适配 |
| 攻击向量 | Network | Adjacent(相邻网络) |
| 含义 | 「裸奔即可打」 | 「需要一堆前提才打得成」 |
实践建议:不要停在分数之争上 。判断标准应该是「我环境里这条脆弱代码路径活不活」------tlsProcessPendingData() 不执行,分数再高也跟你无关;它执行且端口可达,按 7.5 也该当 9.8 处理(先补了再说)。第三方分析(CODERCOPS 等)也建议:在前提不清时按 pre-auth 可利用的假设处理------多打一个补丁的成本远低于赌错方向的代价。
排查:我的 Redis 在攻击面内吗
bash
# 1. 看是否开了 TLS 终止(关键判定)
redis-cli CONFIG GET tls-port
# 返回 0 / 空 → 本机没配 TLS → 此 CVE 不达(版本照升)
# 返回非 0(如 6380)→ 在攻击面内,尽快升级
# 2. 或直接查配置文件
grep -E '^tls-port|^port' /etc/redis/redis.conf
# 3. 确认当前版本
redis-server --version
# 对照修复矩阵(见下)
# 4. 看 TLS 端口是否暴露到不可信网络
ss -tlnp | grep 6380 # LISTEN 地址是 0.0.0.0/:: 且前面没代理 → 风险高
修复版本矩阵
| 发行线 | 修复版本 |
|---|---|
| Redis OSS 8.x | 8.10.1 / 8.8.2 / 8.6.6 / 8.4.6 / 8.2.9 |
| Redis OSS 7.x | 7.4.11 / 7.2.16 |
| Redis OSS 6.2 | 6.2.24 |
| Redis Software | 8.2.0-46 / 8.0.20-96 / 7.22.2-179 / 7.8.6-303 |
| Redis Cloud | Essentials 已修补;Pro 修补中(急等可联系 TAM) |
升级动作(以 Ubuntu/Debian 系 + 官方源为例):
bash
# 确认包源是 redis 官方源而非发行版旧源
apt-cache policy redis-server | head -5
# 升级(生产先备份 RDB/AOF)
redis-cli -a '<密码>' BGSAVE
sudo apt-get update && sudo apt-get install --only-upgrade redis-server
# 重启后验证
redis-server --version
redis-cli CONFIG GET tls-port
部署形态决策表:你的 Redis 属于哪一类
| 部署形态 | tlsProcessPendingData 执行? | 本 CVE 风险 | 建议 |
|---|---|---|---|
| 代理层终止 TLS(Nginx/HAProxy/LB),Redis 纯明文内网 | 否 | 低(不达) | 正常补丁周期升级即可 |
| Redis 自终止 TLS(tls-port 开启),仅内网可达 | 是 | 中 | 尽快升级 + ACL 收紧 |
| Redis 自终止 TLS,端口可达不可信网络 | 是 | 高 | 立即升级 + 网络隔离 + 强认证 |
| 托管服务(Redis Cloud 等) | - | 由厂商处理 | Essentials 已修补;Pro 联系 TAM 加急 |
判断技巧 :不确定自己是不是「Redis 自终止 TLS」?一条命令:redis-cli CONFIG GET tls-port 返回 0 就是没开;再 ss -tlnp | grep <tls-port> 看监听地址。两步就能完成风险分级。
升级演练:从检测到回滚
安全升级不是「装完就行」,生产 Redis 升级要按可回滚的流程走:
bash
# ① 升级前快照(数据完整性)
redis-cli -a '<密码>' BGSAVE
# 等 bgsave 完成
redis-cli -a '<密码>' LASTSAVE
# ② 记录当前版本与配置(回滚依据)
redis-server --version > /tmp/redis_version_before.txt
redis-cli -a '<密码>' CONFIG GET * 2>/dev/null | grep -E "tls-port|port|requirepass|appendonly" || true
cp /etc/redis/redis.conf /etc/redis/redis.conf.bak.$(date +%Y%m%d)
# ③ 升级
sudo apt-get update && sudo apt-get install --only-upgrade redis-server
# ④ 启动 + 健康验证(不只查进程,要查业务)
sudo systemctl restart redis-server
systemctl is-active redis-server # 进程状态
redis-cli -a '<密码>' ping # 连通性 → PONG
redis-cli -a '<密码>' INFO persistence | grep -E "rdb_last_bgsave_status|aof_last_write_status" # 持久化健康
# 业务验证:让依赖方跑一次真实读写(缓存命中 / 队列生产消费)
# ⑤ 回滚预案(升级后 24h 内异常时执行)
sudo apt-get install redis-server=<旧版本号>
cp /etc/redis/redis.conf.bak.$(date +%Y%m%d) /etc/redis/redis.conf
sudo systemctl restart redis-server
常见坑 :只查 systemctl is-active 不算验证完成------进程活着不代表能读写、不代表持久化正常。至少补 ping + 持久化状态 + 一次业务读写三步。
加固清单:即使升级完也别裸奔
Redis 官方公告的加固建议展开成可执行清单(按优先级):
| 优先级 | 动作 | 命令/配置 |
|---|---|---|
| P0 | 尽快升级到修复版 | 见版本矩阵 |
| P0 | 端口不暴露公网/不可信网络 | 防火墙只放行内网/代理来源 IP;bind 只写内网地址 |
| P1 | 强制认证 | requirepass / Redis 6+ 用 ACL user default on ><强密码> ~* +@all |
| P1 | 最小权限 ACL | 应用账号只给需要的命令:user app on ><密码> ~cache:* +get +set +expire |
| P2 | 移除高危命令权限 | 不用的账号不给 CLIENT KILL、Lua(EVAL/SCRIPT)、Pub/Sub 类权限 |
| P2 | TLS 部署形态评估 | 能走代理终止 TLS 就走代理;必须自终止则确保 ACL + 网络双收紧 |
ACL 最小化示例:
sql
# redis.conf 或 CONFIG SET
user default off
user app on >$(openssl rand -base64 24) ~app:* +@string +@list +@hash +@expire +ping
user admin on >$(openssl rand -base64 24) ~* +@all
Agent 基建视角:为什么这篇值得运维和 AI 团队都看
LangGraph checkpoint(上一期 #12 刚拆过 Redis checkpointer 注入)、语义缓存、会话记忆、Celery/任务队列------Agent 生产栈里一半的「记忆与队列」直接压在 Redis 上。很多 AI 团队为了「安全」给 Redis 开了 TLS 就以为万事大吉,实际:
- TLS 终止在 Redis 自己身上 = 引入整条 OpenSSL + pending-data 处理代码面,包括这类 UAF;
- 「开了 TLS」挡不住「命令权限过大」------CLIENT KILL / EVAL / Pub/Sub 权限过大本身是独立风险面;
- 多租户 Agent 应用里 Redis 往往被 LangGraph checkpointer、语义缓存、队列多个组件共享,一个组件的权限需求会拖高整个实例的权限水位。
给 Agent 团队的运维建议:Redis 实例按用途拆分(checkpoint 库 / 缓存库 / 队列库分开或至少分 db/ACL 命名空间),每个用途最小权限;TLS 能前移到代理就前移;版本跟着官方安全公告走,别停在「能跑就行」。
Agent 栈里 Redis 的典型承载与风险对应:
| Redis 承载 | 典型组件 | 本 CVE 影响 | 建议 |
|---|---|---|---|
| Agent 状态/checkpoint | LangGraph Redis checkpointer | 服务崩溃 → 会话恢复失败 | 升级 + 实例拆分 + 持久化备份 |
| 语义缓存 | Redis LangCache / 自研 | 缓存服务抖动 → 上游连锁 | 升级 + 熔断/降级策略 |
| 会话记忆 | Redis 存 session/记忆 | 崩溃丢会话上下文 | 升级 + AOF 开启 |
| 任务队列 | Celery/RQ broker | 队列断连 → 任务堆积 | 升级 + 重连退避确认 |
同一实例被多个组件共享时,任何一个组件升级窗口都会变成全栈维护窗口------拆开之后,每个组件的风险面独立、升级互不拖累。
实战:一次「TLS 崩了」的排查 walkthrough
假设你收到告警「Redis 实例重启了」,且这台 Redis 开了 tls-port。别急着归因网络抖动,按回合制排查:
回合 1:看崩溃痕迹
bash
# Redis 崩溃会在日志留下堆栈(含函数名)
sudo journalctl -u redis-server --since "1 hour ago" | grep -A 30 "Crashed\|SIGSEGV\|Backtrace"
# 若看到 tlsProcessPendingData / tls 相关帧 → 高度怀疑 CVE-2026-81934 相关路径
日志里如果出现 Segmentation fault + 栈顶含 tls 帧,先别怀疑业务代码------这是 Redis 自己进程内的崩溃,业务代码再错也崩不了 Redis 进程。
回合 2:确认部署形态
bash
redis-cli -a '<密码>' CONFIG GET tls-port # 6380?还是 0?
ss -tlnp | grep 6380 # 监听在 0.0.0.0 还是内网地址?
redis-server --version # 对照修复矩阵
tls-port= 0 → 不是这个 CVE(继续查其他原因,比如 OOM/磁盘);tls-port≠ 0 且版本低于修复线 → 按本 CVE 处理,升级优先;tls-port≠ 0 且版本已修复 → 仍可能(补丁没覆盖全部触发形态),联系官方/查更新补丁。
回合 3:临时止血与长期修复
bash
# 临时:如果业务允许,先把 TLS 端口摘了走代理(切部署形态)
redis-cli -a '<密码>' CONFIG SET tls-port 0
# 长期:升级修复版 + 网络隔离(见上节升级演练)
回合 4:防复发记录
把「版本 + tls-port 状态 + 监听地址 + 崩溃日志片段」记入变更单,标注 CVE-2026-81934 排查结论------下次同告警直接对表,不用重新推演。
常见误区表(运维视角)
| 误区 | 真相 |
|---|---|
| 「Redis 崩了是内存不够」 | 先看崩溃栈再下结论------UAF 类崩溃和 OOM 杀进程在日志里是两回事 |
| 「开了 TLS 就安全了」 | TLS 只加密传输,不防命令滥用、不防服务端自身内存 bug |
| 「有密码就行」 | ACL 最小权限比单一 requirepass 重要得多------权限过大 = 攻击者拿到后能做的事多 |
| 「云厂商 Redis 跟我无关」 | 托管也要确认厂商修补状态(本 CVE:Essentials 已修,Pro 还在进行) |
| 「CVSS 7.5 不急」 | 分数基于「已认证 + 苛刻条件」假设;公开 PoC 出现后按更高风险处理 |
总结:三层理解
- 初级 :
redis-cli CONFIG GET tls-port是 0 就不用慌(此洞不达),但版本仍建议升到 8.10.1 / 7.4.11 / 6.2.24 等修复版;开了 tls-port 且端口可达 → 立即升级。 - 中级:理解 UAF 三要素------迭代器持引用、循环中释放、释放后读取。这类漏洞的本质是内存生命周期管理错误,出现在网络服务里意味着「崩溃起步、RCE 封顶」,取决于释放后内存被什么复用。
- 记忆锚点 :「漏洞达不达得到你」看的是脆弱代码路径活不活,不是 CVSS 分数 。TLS 终止在代理层,
tlsProcessPendingData不执行,9.8 也与你无关;它执行且裸奔,7.5 也要当 9.8 处理。升级、ACL、网络隔离三件事做完,评分争议就不再影响你的决策。
同类家族:Redis 近期安全事件速查
| 时间 | 事件 | 类型 | 要点 |
|---|---|---|---|
| 2026-08 | CVE-2026-81934(本文) | TLS pending-data UAF | 自终止 TLS 场景,评分 9.8 vs 7.5 争议 |
| 2026-05 | Redis 五连 CVE 批次 | 多类型 | 社区对 Redis 默认配置/ACL 关注升温 |
| 2025-11 | LangGraph CVE-2026-27022 | RediSearch 注入 | Redis 作为 Agent checkpoint 存储的注入面(见上期) |
运维动作摘要 :今天下班前完成三件事------① CONFIG GET tls-port 确认形态;② 对照版本矩阵确认是否低于修复线;③ 低于修复线就排升级窗口,别等告警来推你。
原始出处 :Redis 官方安全公告 Security Advisory: CVE-2026-81934(2026-08-28);NVD CVE-2026-81934;CODERCOPS《CVE-2026-81934: Redis TLS Use-After-Free, Who's Exposed》;Redis Software / AWS ALAS 修复状态页