admin 发表于 2025-3-25 17:25:30

Next.js and the corrupt middleware: the authorizing artifact

<h1>Next.js and the corrupt middleware: the authorizing artifact</h1>
<p>Next.js 和损坏的中间件:授权工件</p>
<h1>Next.js and the corrupt middleware: the authorizing artifact</h1>
<p>Next.js 和损坏的中间件:授权工件<br />
Published in <em>zhero_web_security</em> , 2025<br />
发表于 <em>zhero_web_security</em>, 2025 年</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-11.png" alt="" /></p>
<h2>Introduction 介绍</h2>
<p>Recently, Yasser Allam, known by the pseudonym inzo_, and I, decided to team up for some research. We discussed potential targets and chose to begin by focusing on <a href="https://github.com/vercel/next.js">Next.js</a> (<em>130K stars on github, currently downloaded + 9,4 million times per week</em> ), a framework I know quite well and with which I already have fond memories, as evidenced by <a href="https://zhero-web-sec.github.io/research-and-things/">my previous work</a>. Therefore, the “we” throughout this paper will naturally refer to the two of us.<br />
最近,我和 Yasser Allam(笔名 inzo_)决定组队进行一些研究。我们讨论了潜在的目标,并选择从 <a href="https://github.com/vercel/next.js">Next.js</a> ( *GitHub 上 13 万颗星,目前每周下载量超过 940 万次 * )开始,这是我非常熟悉的一个框架,我对它有着美好的回忆,这从<a href="https://zhero-web-sec.github.io/research-and-things/">我之前的工作</a>中可以看出来。因此,本文中的“我们”自然是指我们两个。</p>
<p>Next.js is a comprehensive javascript framework based on React, packed with numerous features — the perfect playground for diving into the intricacies of research. We set out, fueled by faith, curiosity, and resilience, to explore its lesser-known aspects, hunting for hidden treasures waiting to be found.<br />
Next.js 是一个基于 React 的综合 JavaScript 框架,具有众多功能,是深入研究复杂问题的理想场所。我们怀着信念、好奇心和韧性,开始探索其鲜为人知的方面,寻找等待被发现的隐藏宝藏。</p>
<p>It didn’t take long before we uncovered a great discovery in the middleware. The impact is considerable, with all versions affected, and no preconditions for exploitability — as we’ll demonstrate shortly.<br />
不久之后,我们在中间件中发现了一个重大发现。影响相当大,所有版本都会受到影响,而且没有任何先决条件可以利用 — 我们稍后会演示。</p>
<h2>Index 指数</h2>
<ul>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-1">The Next.js middleware Next.js 中间件</a></li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-2">The authorizing artifact artifact: old code, 0ld treasure 授权神器:旧代码,0ld 宝藏</a>
<ul>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-2-1">Execution order and middlewareInfo.name 执行顺序和 middlewareInfo.name</a></li>
</ul>
</li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-3">The authorizing artifact: nostalgia has its charm, but living in the moment is better 授权神器:怀旧固然有魅力,但活在当下更好</a>
<ul>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-3-1">/src directory /src 目录</a></li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-3-2">Max recursion depth 最大递归深度</a></li>
</ul>
</li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-4">Exploits 漏洞</a>
<ul>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-4-1">Authorization/Rewrite bypass 授权/重写绕过</a></li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-4-2">CSP bypass CSP 绕过</a></li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-4-3">DoS via Cache-Poisoning (what?) 通过缓存中毒进行 DoS 攻击(什么?)</a></li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-4-4">Clarification 澄清</a></li>
</ul>
</li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-5">Security Advisory - CVE-2025-29927 安全公告 - CVE-2025-29927</a></li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-6">Disclaimer 免责声明</a></li>
<li><a href="https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware#section-7">Conclusion 结论</a></li>
</ul>
<h2>The Next.js middleware Next.js 中间件</h2>
<blockquote>
<p>Middleware allows you to run code before a request is completed. Then, based on the incoming request, you can modify the response by rewriting, redirecting, modifying the request or response headers, or responding directly (<em>Next.js <a href="https://nextjs.org/docs/app/building-your-application/routing/middleware">documentation</a></em> ).<br />
中间件允许您在请求完成之前运行代码。然后,根据传入的请求,您可以通过重写、重定向、修改请求或响应标头或直接响应来修改响应( <em>Next.js<a href="https://nextjs.org/docs/app/building-your-application/routing/middleware">文档</a></em> )。</p>
</blockquote>
<p>Next.js, being a complete framework, has its own middleware — an important and widely used feature. Its use cases are numerous, but the most important ones include:<br />
Next.js 是一个完整的框架,它有自己的中间件——一个重要且广泛使用的功能。它的用例很多,但最重要的包括:</p>
<ul>
<li>Path rewriting 路径重写</li>
<li>Server-side redirects 服务器端重定向</li>
<li>Adding elements such as headers (CSP, etc.) to the response<br />
向响应添加标头(CSP 等)等元素</li>
<li>And most importantly: Authentication and Authorization<br />
最重要的是:身份验证和授权</li>
</ul>
<p>A common use of middleware is for <strong>authorization</strong> , which involves <strong>protecting certain paths</strong>based on specific conditions.<br />
中间件的一个常见用途是<strong>授权 ** ,它涉及根据特定条件</strong>保护某些路径 ** 。</p>
<blockquote>
<p>Authentication and Authorization: Ensure user identity and check session cookies before granting access to specific pages or API routes (<em>Next.js <a href="https://nextjs.org/docs/app/building-your-application/routing/middleware">documentation</a></em> ).<br />
身份验证和授权:在授予对特定页面或 API 路由的访问权限之前,确保用户身份并检查会话 cookie( <em>Next.js<a href="https://nextjs.org/docs/app/building-your-application/routing/middleware">文档</a></em> )。</p>
</blockquote>
<p><em>Exemple</em> : When a user attempts to access <code>/dashboard/admin</code> , their request will first go through the middleware, which will check if their session cookies are valid and grant them the necessary permissions. If so, the middleware will forward the request; otherwise, the middleware will redirect the user to a login page:<br />
*示例 * :当用户尝试访问 <code>/dashboard/admin</code>时,他们的请求将首先通过中间件,中间件将检查他们的会话 cookie 是否有效并授予他们必要的权限。如果是,中间件将转发请求;否则,中间件将把用户重定向到登录页面:</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-1.png" alt="" /></p>
<h2>The authorizing artifact: old code, 0ld treasure</h2>
<p>授权神器:旧代码,0ld 宝藏<br />
As a great man once said, <em>talk is cheap, show me the bug</em> , let’s avoid the excess storytelling and get straight to the point; while browsing an older version of the framework (v12.0.7), we came across this <a href="https://github.com/vercel/next.js/blob/v12.0.7/packages/next/server/next-server.ts">piece of code</a>:<br />
正如一位伟人曾经说过的,* 说话很容易,指出错误很容易 * ,让我们避免多余的叙述,直接进入正题;在浏览该框架的旧版本(v12.0.7)时,我们遇到了这样<a href="https://github.com/vercel/next.js/blob/v12.0.7/packages/next/server/next-server.ts">一段代码</a>:</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-3.png" alt="" /></p>
<p>When a next.js application uses a middleware, the <code>runMiddleware</code>function is used, the latter - <em>beyond its main utility</em>- retrieves the value of the <code>x-middleware-subrequest</code>header and uses it <strong>to know if the middleware should be applied or not</strong> . The header value is split to create a list using the column character (<code>:</code> ) as a separator and then checks if this list contains the <code>middlewareInfo.name</code>value.<br />
当 next.js 应用程序使用中间件时,将使用 <code>runMiddleware</code>函数,后者(* 除了其主要实用程序之外 * )检索 <code>x-middleware-subrequest</code>标头的值并使用它**来了解是否应应用中间件 ** 。标头值被拆分以使用列字符( <code>:</code>作为分隔符创建一个列表,然后检查此列表是否包含 <code>middlewareInfo.name</code>值。</p>
<p>This means that if we add the <code>x-middleware-subrequest</code>header with the correct value to our request, the middleware - <em>whatever its purpose</em>- <strong>will be completely ignored</strong> , and the request will be forwarded via <code>NextResponse.next()</code>and will complete its journey to its original destination <strong>without the middleware having any impact/influence on it</strong> . The header and its value act as a <em>universal key</em>allowing rules to be overridden. At this point we already know that we have just unearthed something crazy, we now have to complete the last pieces.<br />
这意味着如果我们将 <code>x-middleware-subrequest</code>标头及其正确值添加到请求中,中间件(* 无论其用途是什么 * )** 都将被完全忽略 ** ,并且请求将通过 <code>NextResponse.next()</code>转发并完成其到达其原始目的地的旅程 **,而中间件不会对其产生任何影响 ** 。标头及其值*充当通用密钥 * ,允许覆盖规则。此时我们已经知道我们刚刚发现了一些疯狂的东西,我们现在必须完成最后的部分。</p>
<p>For our “universal key” to work, its value must contain <code>middlewareInfo.name</code> , but what is it?<br />
为了使我们的“通用密钥”起作用,其值必须包含 <code>middlewareInfo.name</code>,但它是什么?</p>
<h3>Execution order and middlewareInfo.name</h3>
<p>执行顺序和 middlewareInfo.name<br />
The value of <code>middlewareInfo.name</code>is perfectly guessable, it is only <strong>the path in which the middleware is located</strong> . And to know this, it is necessary to take a quick detour to understand how the middleware was configured in older versions.<br />
<code>middlewareInfo.name</code>的值完全可以猜测,它只是**中间件所在的路径 ** 。要知道这一点,有必要快速了解一下旧版本中中间件的配置方式。</p>
<p>To begin with, before version 12.2 - version during which a <a href="https://nextjs.org/docs/messages/middleware-upgrade-guide">change in middleware conventions</a> was made - the file had to be named <code>_middleware.ts</code> . Furthermore, the <code>app</code>router was only released in version 13 of Next.js. The only router that existed at that time was the <code>pages</code>router, so the file had to be placed inside the <code>pages</code>folder (<em>router specific</em> ).<br />
首先,在版本 12.2(在此期间<a href="https://nextjs.org/docs/messages/middleware-upgrade-guide">对中间件约定进行了更改</a>)之前,该文件必须命名为 <code>_middleware.ts</code>。此外, <code>app</code>路由器仅在 Next.js 版本 13 中发布。当时唯一存在的路由器是 <code>pages</code>路由器,因此该文件必须放在 <code>pages</code>文件夹中(* 特定于路由器 * )。</p>
<p>This information allows us to deduce the exact path of the middleware, and therefore to guess the value of the <code>x-middleware-subrequest</code>header, the latter is simply composed of the <strong>name of the directory</strong>(<em>having the name of the only existing router existing at time T</em> ) and the <strong>name of the file</strong> , respecting the convention of that time consisting of starting with an underscore:<br />
这些信息使我们能够推断出中间件的确切路径,从而猜测 <code>x-middleware-subrequest</code>标头的值,后者仅由<strong>目录名称 ** (* 具有时间 T 时存在的唯一现有路由器的名称 * )和</strong>文件名称** 组成,遵循当时以下划线开头的约定:</p>
<pre><code class="language-plaintext">x-middleware-subrequest: pages/_middleware
</code></pre>
<p>And when we try to bypass our middleware <strong>configured to systematically redirect access attempts</strong>to <code>/dashboard/team/admin</code>to <code>/dashboard</code> :<br />
当我们尝试绕过配置的中间件,系统地将对 <code>/dashboard/team/admin</code> ** 访问尝试重定向** 到 <code>/dashboard</code>时:</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-2.png" alt="" /><em>akhy, we are in ⚔️<br />
akhy,我们在⚔️</em></p>
<p>We can now <strong>completely bypass the middleware</strong> , and therefore any protection system based on it, starting with <strong>authorization</strong> , as in our example above. It’s pretty crazy, but there are other points to consider.<br />
现在,我们可以<strong>完全绕过中间件 ** ,从而绕过任何基于它的保护系统,从</strong>授权** 开始,就像我们上面的例子一样。这很疯狂,但还有其他几点需要考虑。</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-12.png" alt="" /></p>
<p>Versions prior to 12.2 allowed nested routes to place one or more <code>_middleware</code>files anywhere in the tree (starting from the <code>pages</code>folder) and had an execution order, as we can see in this screenshot of <a href="https://web.archive.org/web/20211029042818/https://nextjs.org/docs/middleware">the old documentation</a> retrieved from the good old web archive:<br />
12.2 之前的版本允许嵌套路由将一个或多个 <code>_middleware</code>文件放置在树中的任何位置(从 <code>pages</code>文件夹开始),并且具有执行顺序,正如我们在从旧的网络档案中检索到的<a href="https://web.archive.org/web/20211029042818/https://nextjs.org/docs/middleware">旧文档</a>的屏幕截图中所看到的那样:</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-4.png" alt="" /></p>
<p><strong>Ok, what does this mean for our exploit?<br />
好的,这对于我们的利用意味着什么?</strong></p>
<blockquote>
<p>possibilities = numbers of levels in the path<br />
可能性 = 路径中的级别数</p>
</blockquote>
<p>So, to gain access to <code>/dashboard/panel/admin</code>(<em>protected by middleware</em> ), there are three possibilities regarding the value of <code>middlewareInfo.name</code> , and therefore of <code>x-middleware-subrequest</code> :<br />
因此,要访问 <code>/dashboard/panel/admin</code>(* 受中间件保护 * ), <code>middlewareInfo.name</code>的值有三种可能性,因此 <code>x-middleware-subrequest</code>的值也有三种可能性:</p>
<pre><code class="language-plaintext">pages/_middleware
</code></pre>
<p>or 或者</p>
<pre><code class="language-plaintext">pages/dashboard/_middleware
</code></pre>
<p>or 或者</p>
<pre><code class="language-plaintext">pages/dashboard/panel/_middleware
</code></pre>
<h2>The authorizing artifact: nostalgia has its charm, but living in the moment is better</h2>
<p>授权神器:怀旧固然有魅力,但活在当下更好<br />
Until now, we thought that only versions prior to version 13 were vulnerable because the middleware had been moved in the source code, and we hadn’t yet covered some of its areas. We figured they must have noticed the vulnerability and fixed it before the major changes made in version 13, so we reported the vulnerability to the framework maintainers and continued our research.<br />
到目前为止,我们认为只有版本 13 之前的版本存在漏洞,因为中间件已移至源代码中,而我们尚未涵盖其中的一些区域。我们认为他们一定已经注意到了这个漏洞,并在版本 13 进行重大更改之前修复了它,因此我们向框架维护人员报告了该漏洞并继续研究。</p>
<p>To our big surprise, we discovered two days after this initial discovery that <strong>all versions of next.js</strong>—<em>starting with version 11.1.4</em> — <strong>were vulnerable..!</strong>The code is no longer in the same location, and the exploit’s logic has changed slightly.<br />
令我们大吃一惊的是,我们在最初发现该漏洞两天后发现,** 所有版本的 next.js**(* 从 11.1.4 版本开始 * )** 都存在漏洞。**代码不再位于同一位置,并且漏洞利用的逻辑也略有改变。</p>
<p>As explained previously, starting with version 12.2, the file no longer contains underscores and must simply be named <code>middleware.ts</code> . Furthermore, it must <strong>no longer be located in the pages folder</strong>(<em>which is convenient for us because starting with version 13, the router app is introduced, and that would have doubled the number of possibilities</em> ).<br />
如前所述,从版本 12.2 开始,该文件不再包含下划线,而必须简单地命名为 <code>middleware.ts</code>。此外,它**不能再位于 pages 文件夹中 ** (* 这对我们来说很方便,因为从版本 13 开始,引入了路由器应用程序,这将使可能性增加一倍 * )。</p>
<p>With that in mind, the payload for the first versions starting with version 12.2 is very simple:<br />
考虑到这一点,从版本 12.2 开始的第一个版本的有效载荷非常简单:</p>
<pre><code class="language-plaintext">x-middleware-subrequest: middleware
</code></pre>
<h3>/src directory /src 目录</h3>
<p>It should also be taken into account that Next.js gives the possibility to create a <code>/src</code>directory:<br />
还应该考虑到 Next.js 提供了创建 <code>/src</code>目录的可能性:</p>
<blockquote>
<p>As an alternative to having the special Next.js app or pages directories in the root of your project, Next.js also supports the common pattern of placing application code under the src directory. (Next.js <a href="https://nextjs.org/docs/app/building-your-application/configuring/src-directory">documentation</a>)<br />
除了在项目根目录中放置特殊的 Next.js 应用程序或页面目录外,Next.js 还支持将应用程序代码放置在 src 目录下的常见模式。(Next.js<a href="https://nextjs.org/docs/app/building-your-application/configuring/src-directory">文档</a>)</p>
</blockquote>
<p>In which case the payload would be:<br />
在这种情况下,有效载荷将是:</p>
<pre><code class="language-plaintext">x-middleware-subrequest: src/middleware
</code></pre>
<p>So, a total of <strong>two possibilities, regardless of the number of levels in the path</strong> . This simplifies the exploit for the few versions concerned.<br />
因此,** 无论路径有多少层,总共有两种可能性 ** 。这简化了相关版本的漏洞利用。</p>
<p>From the latest versions, it changes a little again (<em>last time, we promise</em> ).<br />
从最新版本来看,它又发生了一些变化(* 上次,我们保证 * )。</p>
<h3>Max recursion depth 最大递归深度</h3>
<p>On more recent versions the logic has changed slightly again, take a look at this <a href="https://github.com/vercel/next.js/blob/v15.1.7/packages/next/src/server/web/sandbox/context.ts">piece of code</a> :<br />
在较新的版本中,逻辑又略有改变,看一下这段<a href="https://github.com/vercel/next.js/blob/v15.1.7/packages/next/src/server/web/sandbox/context.ts">代码</a>:</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-5.png" alt="" /><em>v15.1.7</em></p>
<p>The value of the header <code>x-middleware-subrequest</code>is retrieved in order to form a list whose separator is the column character, as before. But this time, the condition for the request to be forwarded directly - <em>ignoring the rules of the middleware</em>- is different:<br />
像以前一样,获取标头 <code>x-middleware-subrequest</code>的值,以便形成以列字符为分隔符的列表。但这次,直接转发请求的条件(* 忽略中间件的规则 * )有所不同:</p>
<p>The value of the constant depth <strong>must be greater or equal than the value of the constant</strong><code>MAX_RECURSION_DEPTH</code>(which is <code>5</code> ), when assigned, the constant depth is incremented by 1 each time one of the values ​​of the list -<code>subrequests</code> - (being the result of the header value separated by <code>:</code> ) is equal to the value <code>params.name</code>which is simply <strong>the path to the middleware</strong> . And as explained earlier, there are <strong>only two possibilities</strong> : <code>middleware</code>or <code>src/middleware</code> .<br />
常量深度的值<strong>必须大于或等于常量 ** <code>MAX_RECURSION_DEPTH</code>的值(即 <code>5</code>),当赋值时,每当列表 - <code>subrequests</code>- 的值之一(即用 <code>:</code>分隔的标头值的结果)等于值 <code>params.name</code>时,常量深度就会加 1 ,而 params.name 只是</strong>中间件的路径 ** 。正如前面所解释的那样,** 只有两种可能性 ** : <code>middleware</code>或 <code>src/middleware</code>。</p>
<p>So we just need to add the following header/value to our request in order to bypass the middleware:<br />
因此,我们只需要在请求中添加以下标头/值即可绕过中间件:</p>
<pre><code class="language-plaintext">x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
</code></pre>
<p>or 或者</p>
<pre><code class="language-plaintext">x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware
</code></pre>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-13.png" alt="" /></p>
<p><strong>What is this piece of code originally used for?<br />
这段代码原本是用来做什么的?</strong></p>
<p>This seems to be there <a href="https://nextjs.org/blog/cve-2025-29927">to prevent recursive requests</a> from falling into an infinite loop.<br />
这似乎是<a href="https://nextjs.org/blog/cve-2025-29927">为了防止递归请求</a>陷入无限循环。</p>
<h2>Exploits 漏洞</h2>
<p>Since we know you like this, here are some real examples from BBP programs.<br />
因为我们知道您喜欢这个,所以这里有一些来自 BBP 程序的真实示例。</p>
<h3>Authorization/Rewrite bypass</h3>
<p>授权/重写绕过<br />
Here, when we try to access <code>/admin/login</code>we get a <code>404</code> . As we can see in the response header, a path rewrite is performed via the middleware to prevent unauthenticated/inappropriate users from accessing it:<br />
在这里,当我们尝试访问 <code>/admin/login</code>时,我们得到了 <code>404</code>。正如我们在响应头中看到的那样,通过中间件执行了路径重写,以防止未经身份验证/不适当的用户访问它:</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-6.png" alt="" /></p>
<p>But with our <em>authorizing artifact</em> :<br />
但是有了我们的*授权工件 * :</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-7.png" alt="" /></p>
<p>We can access the endpoint without any problems, the middleware being completely ignored. <em>Target Next.js version: 15.1.7</em><br />
我们可以毫无问题地访问端点,中间件被完全忽略。* 目标 Next.js 版本:15.1.7*</p>
<h3>CSP bypass CSP 绕过</h3>
<p>This time the site uses the middleware to set -<em>among other things</em> - the CSP and the cookies :<br />
这次,网站使用中间件来设置 CSP 和 cookie* 等 * :</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-9.png" alt="" /></p>
<p>Let’s bypass it: 让我们绕过它:</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-8.png" alt="" /></p>
<p><em>Target next.js version: 15.0.3<br />
目标 next.js 版本:15.0.3</em></p>
<p><strong>Note:</strong>Notice the difference in payload between the two targets, one of them used the <code>src/</code>directory, the other did not.<br />
<strong>注意:</strong>请注意两个目标之间的有效负载差异,其中一个使用了 <code>src/</code>目录,而另一个则没有。</p>
<h3>DoS via Cache-Poisoning (what?)</h3>
<p>通过缓存中毒进行 DoS 攻击(什么?)<br />
Yes, a cache-poisoning DoS is also possible via this vulnerability. This is obviously not what we’re looking for first, but if no sensitive paths are protected, and nothing more interesting seems exploitable, then certain situations can lead to a CPDoS:<br />
是的,通过此漏洞也可以进行缓存中毒 DoS。这显然不是我们首先要寻找的,但如果没有敏感路径受到保护,并且似乎没有更有趣的可利用内容,那么某些情况可能会导致 CPDoS:</p>
<p>Let’s say a site rewrites its users’ paths based on their geographic location, adding (<code>/en</code> , <code>/fr</code> , etc.), and has not provided a page/resource on the root (<code>/</code> ). If we bypass the middleware, we consequently <strong>avoid the rewrite</strong>and we end up on the root page, the latter not being supposed to be reached, the developers did not provide a page, so we get a <code>404</code>(or a <code>500</code>depending on the config/type of rewrite (full url/path)).<br />
假设某个网站根据用户的地理位置重写其用户的路径,添加( <code>/en</code>、 <code>/fr</code>等),但未在根目录( <code>/</code> ​​ )上提供页面/资源。如果我们绕过中间件,我们<strong>就会避免重写</strong> 并最终进入根页面,而后者不应该被访问,开发人员没有提供页面,因此我们会得到 <code>404</code>(或 <code>500</code>,具体取决于重写的配置/类型(完整 url/路径))。</p>
<p>If the site has a cache/CDN system, it may be possible to <strong>force the caching</strong>of a <code>404</code>response, rendering its pages unusable and <strong>significantly impacting its availability</strong> .<br />
如果站点具有缓存/CDN 系统,则可能会<strong>强制缓存 ** <code>404</code>响应,从而导致其页面无法使用并</strong>严重影响其可用性 ** 。</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-10.png" alt="" /></p>
<h3>Clarification 澄清</h3>
<p>Since the security advisory was released, we’ve received a few inquiries from people concerned about their applications and not understanding the scope of the attack. To be clear, the vulnerable element is the middleware. If it isn’t used (or at least isn’t used for sensitive purposes), there’s nothing to worry about (<em>check the DoS aspect above, though</em> ), since bypassing the middleware won’t bypass any security mechanisms.<br />
自安全公告发布以来,我们收到了一些用户的咨询,他们担心自己的应用程序,不了解攻击的范围。需要明确的是,易受攻击的元素是中间件。如果不使用它(或者至少不用于敏感目的),就没有什么可担心的(* 不过,请查看上面的 DoS 方面 * ),因为绕过中间件不会绕过任何安全机制。</p>
<p>Otherwise, the consequences can be catastrophic, and we encourage you to quickly implement the security advisory’s instructions.<br />
否则,后果可能是灾难性的,我们鼓励您尽快实施安全公告的指示。</p>
<h2>Security Advisory - CVE-2025-29927</h2>
<p>安全公告 - CVE-2025-29927<br />
<strong>Patches 补丁</strong></p>
<ul>
<li>For Next.js 15.x, this issue is fixed in 15.2.3<br />
对于 Next.js 15.x,此问题已在 15.2.3 中修复</li>
<li>For Next.js 14.x, this issue is fixed in 14.2.25<br />
对于 Next.js 14.x,此问题已在 14.2.25 中修复</li>
<li>For Next.js versions 11.1.4 thru 13.5.6 we recommend consulting the below workaround.<br />
对于 Next.js 版本 11.1.4 至 13.5.6,我们建议参考以下解决方法。</li>
</ul>
<p><strong>Workaround 解决方法</strong></p>
<p>If patching to a safe version is infeasible, we recommend that you prevent external user requests which contain the <code>x-middleware-subrequest</code>header from reaching your Next.js application.<br />
如果无法修补到安全版本,我们建议您阻止包含 <code>x-middleware-subrequest</code>标头的外部用户请求到达您的 Next.js 应用程序。</p>
<p><strong>Severity 严重程度</strong></p>
<p><code>CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N</code>(Critical 9.1/10)<code>CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N</code>(严重 9.1/10)</p>
<p><a href="https://github.com/vercel/next.js/security/advisories/GHSA-f82v-jwr5-mffw">https://github.com/vercel/next.js/security/advisories/GHSA-f82v-jwr5-mffw</a></p>
<p><strong>More 更多的</strong></p>
<p>At the time of writing, applications on Vercel and Netlify are apparently no longer vulnerable (<em>Update: Cloudflare <a href="https://x.com/elithrar/status/1903526240847331362">has moved this rule to opt-in only</a> due to numerous false positives that fail to distinguish between requests from legitimate users and those from potential attackers</em> ):<br />
在撰写本文时,Vercel 和 Netlify 上的应用程序显然不再存在漏洞(* 更新:Cloudflare<a href="https://x.com/elithrar/status/1903526240847331362">已将此规则移至仅限选择加入,</a> 因为存在大量误报,无法区分来自合法用户的请求和来自潜在攻击者的请求 * ):</p>
<p><img src="https://zhero-web-sec.github.io/images/next-middleware-14.png" alt="" /></p>
<p><em><a href="https://x.com/nextjs/status/1903522002431857063">https://x.com/nextjs/status/1903522002431857063</a></em></p>
<h2>Disclaimer 免责声明</h2>
<p>This research publication is for educational purposes only, whether to help developers understand the root causes of the problem or to inspire researchers/bug hunters in their future campaigns. This publication accompanies the security advisory and provides clarifications/explanations regarding its nature, as the latter has already revealed the header responsible for the vulnerability (<em>the <a href="https://github.com/vercel/next.js/commit/52a078da3884efe6501613c7834a3d02a91676d2">commit diff</a> too</em> ).<br />
本研究出版物仅用于教育目的,无论是帮助开发人员了解问题的根本原因,还是激励研究人员/漏洞猎人开展未来的活动。本出版物随安全公告一起发布,并提供了有关其性质的澄清/解释,因为后者已经揭示了导致漏洞的标头(*<a href="https://github.com/vercel/next.js/commit/52a078da3884efe6501613c7834a3d02a91676d2">提交差异</a>也是如此 * )。</p>
<p>We obviously disclaim any unethical use of this article.<br />
我们明确否认对本文有任何不道德的使用。</p>
<h2>Conclusion 结论</h2>
<p>As highlighted in this paper, this vulnerability has been present for several years in the next.js source code, evolving with the middleware and its changes over the versions. A critical vulnerability can occur in any software, but when it affects one of the most popular frameworks, it becomes particularly dangerous and can have severe consequences for the broader ecosystem. As mentioned earlier, Next.js is downloaded nearly 10 million times a week at the time of writing. It is widely used across critical sectors, from banking services to blockchain. The risk is even greater when the vulnerability impacts a mature feature that users rely on for essential functions like authorization and authentication.<br />
正如本文所强调的,该漏洞在 next.js 源代码中已经存在了好几年,随着中间件及其版本的变化而不断演变。任何软件都可能出现严重漏洞,但当它影响到最流行的框架之一时,就会变得特别危险,并可能对更广泛的生态系统造成严重后果。如前所述,截至撰写本文时,Next.js 每周的下载量接近 1000 万次。它广泛应用于从银行服务到区块链等关键领域。当漏洞影响用户依赖的授权和身份验证等基本功能的成熟功能时,风险会更大。</p>
<p>The vulnerability took a few days to be addressed by the Vercel team, but it should be noted that once they became aware of it, a fix was committed, merged, and implemented in a new release <strong>within a few hours</strong>(<em>including backports</em> ).<br />
Vercel 团队花了几天时间才解决这个漏洞,但值得注意的是,一旦他们意识到这个漏洞,就会<strong>在几个小时内</strong> 提交、合并并在新版本中实施修复(* 包括反向移植 * )。</p>
<p><strong>Timeline</strong> :<br />
**时间线 ** :</p>
<ul>
<li><strong>02/27/2025</strong> : vulnerability reported to the maintainers (<em>specifying that only versions between 12.0.0 and 12.0.7 were vulnerable, which was our understanding at the time</em> )<br />
*<em>2025 年 2 月 27 日 ** :向维护人员报告了漏洞(</em> 指出只有 12.0.0 到 12.0.7 之间的版本存在漏洞,这是我们当时的理解 * )</li>
<li><strong>03/01/2025</strong> : second email sent explaining that <strong>all versions were ultimately vulnerable</strong> , including the latest stable releases<br />
<strong>2025 年 3 月 1 日 ** :发送第二封电子邮件,解释称</strong>所有版本最终都存在漏洞 ** ,包括最新的稳定版本</li>
<li><strong>03/05/2025</strong> : initial response received from the Vercel team explaining that versions 12.x were no longer supported/maintained (<em>probably hadn’t read the second email/security advisory template indicating that all were vulnerable</em> )<br />
*<em>2025 年 3 月 5 日 ** :收到 Vercel 团队的初步回复,解释称版本 12.x 不再受支持/维护(</em> 可能没有阅读第二封电子邮件/安全公告模板,表明所有版本都存在漏洞 * )</li>
<li><strong>03/05/2025</strong> : another email sent so that the team could quickly take a look at the second email/security advisory template<br />
**2025 年 3 月 5 日 ** :又发送了一封电子邮件,以便团队可以快速查看第二封电子邮件/安全公告模板</li>
<li><strong>03/11/2025</strong> : another email sent to find out whether or not the new information had been taken into account<br />
**2025 年 3 月 11 日 ** :又发送了一封电子邮件,以了解新信息是否已被考虑在内</li>
<li><strong>03/17/2025</strong> : email received from the Vercel team confirming that the information had been taken into account<br />
**2025 年 3 月 17 日 ** :收到 Vercel 团队的电子邮件,确认已考虑到该信息</li>
<li><strong>03/18/2025</strong> : email received from the Vercel team: the report had been accepted, and the patch was implemented. Version 15.2.3 was released a few hours later, containing the fix (<em>+backports</em> )<br />
**2025 年 3 月 18 日 ** :收到 Vercel 团队的电子邮件:报告已被接受,补丁已实施。几个小时后,版本 15.2.3 发布,包含修复程序( <em>+backports</em>)</li>
<li><strong>03/21/2025</strong> : publication of the security advisory<br />
**2025 年 3 月 21 日 ** :发布安全公告</li>
</ul>
<p>To conclude, the search for zero-day vulnerabilities is only exciting and adrenaline-pumping when a lead emerges; the rest of the time, it’s an uncertain journey—rewarding in knowledge for the curious and relatively long for the impatient. Don’t hesitate to team up; desert crossings are easier to navigate in groups.<br />
总而言之,只有当线索出现时,寻找零日漏洞才会令人兴奋和肾上腺素激增;其余时间,这是一段不确定的旅程——对于好奇的人来说,知识是值得的,而对于没有耐心的人来说,则相对较长。不要犹豫,组队吧;成群结队穿越沙漠更容易。</p>
<p>Further research in the pipeline, follow us on our respective X accounts to stay connected.<br />
正在进行进一步的研究,请关注我们各自的 X 帐户以保持联系。</p>
<p>Thank you for reading. 感谢您的阅读。</p>
页: [1]
查看完整版本: Next.js and the corrupt middleware: the authorizing artifact