Sentry Next.js SDK 中间件绕过(CVE-2026-114139)
Sentry 将 CVE-2026-114139 评为严重,CVSS v4.0 9.1:在 webpack 构建中,@sentry/nextjs SDK 会为配置的 tunnelRoute 下所有路径跳过应用中间件,而隧道重写仅处理精确匹配的隧道路径,因此未通过身份验证的请求可在未经中间件授权的情况下访问隧道路径下的路由。受影响版本包括 @sentry/nextjs 9.36.0 至 9.47.1、10.75.2 之前的 10.x,以及 11.0.0-rc.1 之前的 11.0.0 预发布版本。9.47.2、10.75.2 和 11.0.0-rc.1 已修复;目前没有已知在野利用。
要点速览
- @sentry/nextjs 包装您的 Next.js 中间件,以便为 Sentry“隧道”请求跳过中间件。跳过检查的范围比隧道本身更广:隧道路径下的每个请求路径都会被跳过,而不只是隧道端点。
- 能解析到隧道路径下的路由,例如
tunnelRoute: '/monitoring'与/monitoring/foo直接冲突,或根级动态路径段app/[locale]/...,会在不运行中间件的情况下接收这些请求。如果中间件是这些路由唯一的授权位置,授权就会被绕过。 - Sentry 将该漏洞评为严重,CVSS v4.0 9.1,分类为 CWE-693,即保护机制失效。截至 2026 年 10 月 24 日,没有已知在野利用,问题未列入 CISA KEV 目录。npm 包 @sentry/nextjs 在 2026 年 10 月 16-22 日这一周记录了 7,848,686 次下载。
- 升级至 9.47.2、10.75.2 或 11.0.0-rc.1,无需更改配置。如果暂时无法升级,将 tunnelRoute 移到不会解析出任何应用路由的路径,使用 Turbopack 构建,或在中间件之外同时在路由本身实施授权。
我是否受到影响?
以下条件全部成立时,您就受到影响:
- 应用使用受影响版本范围内的 @sentry/nextjs,且设置了
tunnelRoute选项(字符串路径或true)。 - 应用使用 webpack 构建。Turbopack 构建不受影响,它从 Next.js 16 起是
next build的默认方式。 - 应用中有路由能解析到隧道路径下。这可能是直接冲突,例如
tunnelRoute: '/monitoring'下的/monitoring/foo;也可能是路由根部的动态路径段app/[locale]/...,它匹配任何首个路径段。 - 中间件是这些路由唯一实施授权的位置。
Sentry 公告还明确说明了绕过能力的边界:跳过中间件不会赋予请求任何权限,在服务端检查会话的路由仍受保护。Sentry 自身服务和您 Sentry 组织中的数据不受影响。
| 包 | 受影响版本 | 修复版本 |
|---|---|---|
| @sentry/nextjs 9.x | 9.36.0 – 9.47.1 | 9.47.2 |
| @sentry/nextjs 10.x | 10.0.0-alpha.0 – 10.75.1 | 10.75.2 |
| @sentry/nextjs 11 预发布版本 | 11.0.0-alpha.0 – 11.0.0-rc.0 | 11.0.0-rc.1 |
检查已安装的版本和适用条件:
# Installed SDK version
npm ls @sentry/nextjs
node -e "console.log(require('@sentry/nextjs/package.json').version)"
# Lock file check (package-lock.json v2/v3 records the package under "node_modules/@sentry/nextjs")
grep -A1 '"node_modules/@sentry/nextjs"' package-lock.json
# Is the tunnel route configured?
grep -rn "tunnelRoute" next.config.* sentry.* .sentryclirc 2>/dev/null
# Container image check
docker run --rm <your-image> node -e "console.log(require('@sentry/nextjs/package.json').version)"
然后检查哪些路由可以解析到隧道路径下:列出 app/(或 pages/)目录中的路径段,与隧道路径的首段比较。根级动态路径段(例如 [locale])会匹配任意首段。
如何修复?
升级 SDK。跳过逻辑现在仅匹配隧道重写实际处理的请求,无需更改配置:
npm install @sentry/nextjs@10.75.2
# 9.x line: npm install @sentry/nextjs@9.47.2
# 11 prerelease line: npm install @sentry/nextjs@11.0.0-rc.1
# or: pnpm add @sentry/nextjs@10.75.2 | yarn add @sentry/nextjs@10.75.2
如果暂时无法升级,Sentry 公告列出了三种临时措施:
- 将
tunnelRoute设置为不会解析出任何应用路由的路径,或移除此选项。 - 使用 Turbopack 构建,它从 Next.js 16 起是
next build的默认方式。 - 除中间件外,也在路由、布局或数据访问路径中实施授权。
这些措施的局限在于:第一种依赖于应用演进时路由结构始终不发生冲突;第二种改变构建流水线;第三种意味着重复本来希望通过中间件集中管理的授权逻辑。升级则为所有调用方消除 SDK 内部的不匹配。
根本原因是什么?
Next.js 中间件在路由前运行,是常见的授权实施位置。@sentry/nextjs 对 webpack 构建的中间件插桩时,会用 wrapMiddlewareWithSentry 包装中间件函数。它首先检查入站请求是否为 Sentry 隧道请求,若是则立即返回,不调用您的代码。
隧道用于绕过广告拦截器。浏览器事件发送到您自己服务器上的路径,例如 /monitoring,再由 Next.js 重写规则转发给 Sentry。重写仅处理精确匹配的隧道路径,且要求设置 o 和 p 查询参数,分别承载 Sentry 组织和项目标识符。
跳过逻辑使用了范围更广的测试。在修复前,包装器仅检查请求路径是否位于隧道路径下:
// packages/nextjs/src/common/utils/tunnelPathnameMatch.ts (before the fix)
export function isPathnameUnderSentryTunnelRoute(pathname: string, tunnelPath: string): boolean {
return pathname === tunnelPath || pathname.startsWith(`${tunnelPath}/`);
}
包装器会对所有匹配项跳过中间件:
// packages/nextjs/src/common/wrapMiddlewareWithSentry.ts (before the fix)
if (tunnelRoute && typeof tunnelRoute === 'string') {
const req: unknown = args[0];
if (req instanceof Request) {
const url = new URL(req.url);
const isTunnelRequest = isPathnameUnderSentryTunnelRoute(url.pathname, tunnelRoute);
if (isTunnelRequest) {
// returns a response that lets the request continue, without calling
// the wrapped middleware
return new Response(null, { status: 200, headers: { 'x-middleware-next': '1' } });
}
}
}
漏洞源于两项检查的差异。重写仅处理带有有效 o 和 p 参数的 /monitoring。跳过逻辑却覆盖 /monitoring 和所有以 /monitoring/ 开头的路径,无论是否带有参数。发往 /monitoring/foo 的请求不会重写到 Sentry,而会由 Next.js 路由到应用。但包装器已经返回,因此该请求永远不会运行您的中间件。
一句话概括:中间件跳过逻辑回答的是“此路径是否位于隧道路由下?”,而它本应回答“此请求是否确实会由隧道重写处理?”。这两个集合的差集,恰好就是未经中间件身份验证检查便到达应用路由的请求。
如何利用?
目前没有公开概念验证,截至 2026 年 10 月 24 日也没有已知在野利用。公告和补丁描述的攻击路径如下:
- 目标应用将
tunnelRoute设置为某个路径,通常是/monitoring,并使用 webpack 构建。 - 应用有路由可解析到隧道路径下:可能直接冲突,也可能是
app/[locale]/page.tsx之类的根级动态路径段,将/monitoring匹配为 locale 值。 - 攻击者向该路由路径发送未通过身份验证的请求。
- SDK 中间件包装器发现路径位于隧道路由下,便返回继续处理的响应。应用中间件的主体,包括其中的授权逻辑,完全不会运行。
- Next.js 将请求分发至路由处理器。如果处理器与数据之间没有任何环节重新检查会话,请求就会像已经通过中间件检查一样得到处理。
利用仅需普通 HTTP 请求。其效果完全取决于哪些功能仅由应用中间件守护:身份验证重定向、租户检查、功能准入控制或路由级授权。
攻击流程
发送未通过身份验证的请求"] --> B["SDK 中间件包装器:
路径位于隧道路由下"] B --> C["包装器返回继续处理的
响应,中间件从未运行"] C --> D["隧道重写不匹配:
Next.js 将请求路由到应用"] D --> E["路由处理器在未经中间件授权的
情况下处理请求"] E --> F["影响取决于哪些功能
仅由中间件保护"]
失效检查位于 B:跳过决策的范围比它要配合的重写规则更广。
攻击者能做什么?
在缺少中间件检查的情况下,读取或操作受影响路由暴露的任何内容。公告将影响限定为存在漏洞系统的机密性和完整性;CVSS v4.0 向量为 AV:N/AC:L/AT:P/PR:N/UI:N,不需要权限或用户交互。之所以标注存在攻击前提,是因为配置条件必须同时满足:设置 tunnelRoute、使用 webpack 构建、有路由可解析到隧道路径下,并且只在中间件实施授权。
公告指出,这种绕过不会赋予任何权限,在服务端检查会话的路由仍受保护。Sentry 自身服务和您 Sentry 组织中的数据不受影响。
为什么修复有效?
修复对应拉取请求 #24499,并通过 #24565 和 #24760 回移到旧版本,用精确匹配重写实际处理请求的函数替换路径前缀测试:
// packages/nextjs/src/common/utils/tunnelPathnameMatch.ts (after the fix)
/**
* Returns true only for requests the tunnel rewrite (see `setUpTunnelRewriteRules`) would serve.
*
* This decides whether the user's middleware is skipped, so it must never be broader than the rewrite:
* anything it matches that Next.js does not rewrite to Sentry reaches the app without middleware.
*/
export function isSentryTunnelRequest(request: Request, tunnelPath: string): boolean {
// The SDK transport only ever sends POST requests
if (request.method !== 'POST') {
return false;
}
const url = new URL(request.url);
if (url.pathname !== tunnelPath && url.pathname !== `${tunnelPath}/`) {
return false;
}
// Next.js evaluates `has` conditions against the last value of a repeated query param, so every value has to qualify
return ['o', 'p'].every(key => {
const values = url.searchParams.getAll(key);
return values.length > 0 && values.every(value => /^\d+$/.test(value));
});
}
包装器现在调用 isSentryTunnelRequest(req, tunnelRoute),替代前缀测试。三个属性让两端保持一致:只接受 POST 请求(SDK 传输从不发送其他方法)、只接受带或不带尾部斜杠的精确隧道路径,以及要求 o 和 p 参数均存在且全部为数字,与 Next.js 评估重写 has 条件的方式一致。任何未通过其中一项检查的请求,现在都会像其他请求一样经过您的中间件。
该修复完整解决了所描述的缺口:跳过逻辑和重写现在共享同一个隧道请求定义,代码注释将其明确为不变量。包装器仍只存在于 webpack 构建中;在 Turbopack 构建中它从未启用,因此这类构建始终不受影响。
如何检查是否已遭入侵?
该公告尚未发布入侵指标,也没有已知利用。如果您运行受影响配置并希望审计该模式:
- 在 Web 服务器或 Next.js 访问日志中,查找触及隧道路径下路由、但未经身份验证的请求,将它们与中间件本应拒绝或重定向的请求进行比较:例如发往
/monitoring/...这类路径且不带o和p参数的请求,以及来自中间件本应阻止的来源、发往/en/...这类根级动态路径段的请求。 - 检查受影响路由自身的服务端处理逻辑,寻找任何假定中间件已验证调用者身份的代码。
如果发现本应被中间件阻止却未被阻止的请求,应视为这些会话已在未经身份验证的情况下到达路由,并评估路由返回了什么。
时间线
- 2026 年 9 月 18 日:修复合入主分支(提交 878b685,“使中间件中的隧道请求匹配与隧道重写一致”)。
- 2026 年 9 月 21 日:v10 回移合入(提交 d525a2f);Sentry 于 2026 年 9 月 22 日发布 11.0.0-rc.1 和 10.75.2。
- 2026 年 9 月 24 日:Sentry 发布公告 GHSA-mchm-gjx6-7h55。
- 2026 年 9 月 28 日:v9 回移合入(提交 c122aac);Sentry 于 2026 年 9 月 29 日发布 9.47.2。
- 2026 年 10 月 21 日:NVD 发布 CVE-2026-114139。
- 2026 年 10 月 22 日:GitHub Advisory Database 发布并评审该公告。
- 2026 年 10 月 24 日:本文发布。没有已知在野利用;该问题未列入 CISA KEV 目录。
常见问题
默认配置受影响吗?
隧道路由需要主动启用,因此默认不带 tunnelRoute 的 withSentryConfig 不受影响。公告列出的条件构成完整检查清单:设置 tunnelRoute、webpack 构建、有路由可解析到隧道路径下,以及仅由中间件实施授权。
Turbopack 构建受影响吗?
不受影响。包含跳过逻辑的中间件包装器仅存在于 webpack 集成中。Turbopack 从 Next.js 16 起是 next build 的默认方式,从未具有此跳过逻辑。SDK 自身的代码注释也指出了这一构建一致性问题,而修复仍保留了这一差异。
这能让攻击者进入我的 Sentry 组织吗?
不能。Sentry 公告明确表示,Sentry 自身服务和您 Sentry 组织中的数据不受影响。绕过涉及的是您应用的路由,而非 Sentry 的路由。
为什么监控 SDK 的问题被评为严重?
因为影响取决于您的中间件,而不是 SDK。当中间件是冲突路由唯一的授权边界时,未经身份验证的网络请求就能到达该路由;CVSS v4.0 向量将机密性和完整性影响评为高,评分为 9.1。Sentry 也将其分类为 CWE-693,即保护机制失效。
我的中间件用于重定向而非授权,是否仍需升级?
需要。在方便时升级即可:重定向及其他非授权用途的中间件不构成安全影响,但路由结构会变化,且此次升级没有破坏性更改。
使用 Ostorlab 扫描 Next.js 应用,了解各个仓库中的 @sentry/nextjs 版本和 tunnelRoute 使用情况。
参考资料
- Sentry 公告 GHSA-mchm-gjx6-7h55:https://github.com/getsentry/sentry-javascript/security/advisories/GHSA-mchm-gjx6-7h55 (2026 年 10 月 24 日核查)
- GitHub Advisory Database 条目:https://github.com/advisories/GHSA-mchm-gjx6-7h55 (2026 年 10 月 24 日核查)
- CVE-2026-114139 记录(CVSS v4.0 9.1、CWE-693、受影响范围):https://cveawg.mitre.org/api/cve/CVE-2026-114139 (2026 年 10 月 24 日核查)
- 修复拉取请求 #24499:https://github.com/getsentry/sentry-javascript/pull/24499 (2026 年 10 月 24 日核查)
- 修复提交 878b685(主分支):https://github.com/getsentry/sentry-javascript/commit/878b685c85dc12045e47e1932c96f5381d7ac532 (2026 年 10 月 24 日核查)
- v10 回移提交 d525a2f:https://github.com/getsentry/sentry-javascript/commit/d525a2f6015b47384bc139c30d58e0d5435d52e5 (2026 年 10 月 24 日核查)
- v9 回移提交 c122aac:https://github.com/getsentry/sentry-javascript/commit/c122aac4f29541eb6da494296822c91eab3cf5ae (2026 年 10 月 24 日核查)
- 10.75.2 版本(2026 年 9 月 22 日发布):https://github.com/getsentry/sentry-javascript/releases/tag/10.75.2
- 9.47.2 版本(2026 年 9 月 29 日发布):https://github.com/getsentry/sentry-javascript/releases/tag/9.47.2
- 11.0.0-rc.1 版本(2026 年 9 月 22 日发布):https://github.com/getsentry/sentry-javascript/releases/tag/11.0.0-rc.1
- @sentry/nextjs 的 npm 下载量(2026 年 10 月 16-22 日这一周共 7,848,686 次):https://api.npmjs.org/downloads/point/last-week/@sentry/nextjs (2026 年 10 月 24 日核查)