NVD 9.8、官方 7.5:Redis TLS use-after-free 的评分之争——tlsProcessPendingData 悬指针踩空全解析

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 三步:

  1. 迭代器持有当前节点的引用,准备读取/处理这个节点的数据;
  2. 在遍历循环的某个间隙,命令处理逻辑执行了释放操作------把迭代器还没遍历完的节点 free 掉(pending-data 链表的节点可能因命令处理、连接关闭、超时清理等路径被释放);
  3. 迭代器继续前进,读取已释放的内存------此时该内存可能已被复用(堆上重新分配给了别的对象),读到的是「幽灵数据」,或者直接触发崩溃。

用伪代码描述(基于公开分析的机理还原,非逐行源码):

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 就以为万事大吉,实际:

  1. TLS 终止在 Redis 自己身上 = 引入整条 OpenSSL + pending-data 处理代码面,包括这类 UAF;
  2. 「开了 TLS」挡不住「命令权限过大」------CLIENT KILL / EVAL / Pub/Sub 权限过大本身是独立风险面;
  3. 多租户 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 修复状态页

相关推荐
巴勒个啦6 天前
2026 年 CSS 选型真相:我用 Tailwind v4 + 原生新特性重构了一个组件库
前端·angular.js
starrysky8108 天前
服务全绿、队列却 15 天没人消费?redis-py 8.0 默认切 RESP3 的阻塞命令坑
angular.js
starrysky8108 天前
写个管道就被 BrokenPipeError 打爆?先看 CPython 把 SIGPIPE 藏哪了
angular.js
starrysky81016 天前
画像空不是故障:Honcho peer card 观察者视角源码拆解——1956 条结论为何换不来一张卡
angular.js
starrysky81023 天前
Hindsight 记忆数据增删改实操:70 个 API 端点的 CRUD 地图
angular.js
starrysky81023 天前
从 472ms 到 150ms:Hindsight 的 SQL 模板为何能超越 Text2SQL
angular.js
starrysky8101 个月前
sqlite3.OperationalError: database is locked 为什么 timeout=10 秒没生效?SQLite 锁升级死锁路径完整排障
angular.js
starrysky8101 个月前
SMBus is busy, can't use it! + task blocked 120s - i2c-i801 错误路径释放未获取资源致 hung task(CVE-2026-64205)
angular.js
starrysky8101 个月前
kubectl logs 看不了日志?fsnotify 报 too many open files 的真相是 inotify 实例耗尽
angular.js