Developer platforms, tools and supply chain
@sentry/nextjs: CVE-2026-114139 tunnelRoute middleware bypass
Sentry for Next.js check
The tunnelRoute option of the Sentry SDK for Next.js sends browser events to a path on your own server (for example /monitoring), where a rewrite forwards them to Sentry. To stop your middleware rejecting those envelope requests, the SDK makes the webpack build skip middleware for them. The skip is wider than the rewrite: it covers every path under the tunnel path, while the rewrite serves only the exact tunnel path with valid query parameters. A request in that gap reaches your application and your middleware never runs on it. Skipping middleware grants no privileges by itself.
| CVE | CVE-2026-114139 (CWE-693, advisory GHSA-mchm-gjx6-7h55, published 21 October 2026) |
| Severity | Critical, CVSS 9.1 (v4.0) |
| Affected | @sentry/nextjs 9.36.0 up to 9.47.2, 10.0.0-alpha.0 up to 10.75.2, and 11.0.0-alpha.0 up to 11.0.0-rc.1 |
| Fixed | 9.47.2, 10.75.2 and 11.0.0-rc.1 (all three, and the prerelease tags in between, exist on the npm registry) |
| Vendor workaround | Set tunnelRoute to a path no route of yours can resolve under, or remove the option |
Exploitation needs all four of these at once, which is why this tool judges configuration and not just the version:
tunnelRouteis set (a string path, ortrue);- the app is built with webpack (Turbopack builds are not affected);
- one of your routes resolves under the tunnel path;
- your middleware is the only authorization control for that route.
Quick start
-
Download the script. The repository is mirrored on GitHub and Codeberg; pick a base URL.
# BASE from GitHub: https://raw.githubusercontent.com/PrivacySafe/security-patches/refs/heads/main # BASE from Codeberg: https://codeberg.org/PrivacySafe/security-patches/raw/branch/main # curl -fLO "$BASE/sentry/sentry-nextjs-check.sh" curl -fLO https://raw.githubusercontent.com/PrivacySafe/security-patches/refs/heads/main/sentry/sentry-nextjs-check.sh -
Read it before running it, then make it executable.
less sentry-nextjs-check.sh chmod +x sentry-nextjs-check.sh -
Check this host. By default it searches
/var/www /srv /opt /home; pass directories to narrow it../sentry-nextjs-check.sh check ./sentry-nextjs-check.sh check /srv/myapp
Commands
| Command | What it does |
|---|---|
check [DIR ...] (default) |
Reads the @sentry/nextjs version from package-lock.json, npm-shrinkwrap.json, yarn.lock (v1 and Berry), pnpm-lock.yaml, bun.lock and an installed node_modules copy. For an affected version it reads next.config.* for tunnelRoute, guesses the bundler, and looks for routes that collide with the tunnel path |
version |
Prints the script version |
Exit codes: 0 nothing exposed, 1 an affected version with tunnelRoute on a webpack build (with a collision, or a path that cannot be checked), or a configuration that could not be read, 2 bad arguments.
How each condition is judged
- Condition 1,
tunnelRoute: read fromnext.config.js,.mjs,.cjs,.tsor.mts(andsentry.config.*). A value in a//comment,false, or an absent option means it is not set, and the tool exits0with a reminder to update anyway. - Condition 2, webpack or Turbopack: a
--turbopackor--turboflag in thebuildscript means Turbopack;--webpackmeans webpack; otherwise Next.js 16 or newer is taken to use Turbopack by default, and older versions webpack. If your build is configured some other way, check it yourself. - Condition 3, a colliding route: a directory or file named after the tunnel path in
app/,src/app/,pages/orsrc/pages/, or a root catch-all ([...slug]or[[...slug]]), which matches every path.tunnelRoute: truelets the SDK choose the path, so a collision cannot be checked and the tool treats it as exposed. This check cannot see rewrites, redirects, custom servers or routes defined elsewhere, and says so. - Condition 4, middleware as the only authorization: not visible from outside the application. The tool tells you to review it. Do not rely on middleware alone: check access in the route handler or data layer too.
- Prereleases:
11.0.0-alpha.*,-beta.*and-rc.0are affected;-rc.1and11.0.0are fixed.
Fixing it
Upgrade to 9.47.2, 10.75.2 or 11.0.0-rc.1 or newer and rebuild. Until then, follow the vendor's workaround: set tunnelRoute to a path no route of yours can resolve under, or remove it.
Sources
Before you run it
- The fix. Update
@sentry/nextjsto 9.47.2, 10.75.2 or 11.0.0-rc.1. The vendor's workaround is to settunnelRouteto a path none of your routes can resolve under, or to remove the option. - Exploitation needs all four conditions at once.
tunnelRouteis set, the app is built with webpack (Turbopack builds are not affected), one of your routes resolves under the tunnel path, and your middleware is the only authorization control for that route. Skipping middleware grants no privileges by itself. - Two of the four conditions are judged from file and script contents and one cannot be seen. The script reads
next.config.*fortunnelRoute, guesses the bundler from the build script and the Next.js version, and looks for routes that collide with the tunnel path. Those last two are heuristics. Whether your middleware is the only authorization control for a route cannot be seen from outside the application, so review that yourself. - There is no hunt. No indicators of exploitation have been published.
- It also checks running docker and podman containers, unless you name a directory or set
SCAN_CONTAINERS=0. In each running container, a read-only probe lists the project files this check needs: lockfiles,package.json, route directory names, the few source files that contain'use server',config/auth.phpand similar. Only those files are copied into a private temporary folder, and the normal check judges that folder like a host directory. Only the names of the entries underapp,src/app,pagesandsrc/pagesare copied, as empty files, so no application source leaves the container.next.config.*is copied because it holds thetunnelRoutesetting. A staged symlink is never kept, paths the container reports are validated, and nothing is run in a container beyondfind,grepandtest. The copies are removed on exit. A path shown as.../docker_NAME/PATHis the PATH inside the container NAME. It is skipped when you name directories yourself.
The Security Patches software and this documentation are dedicated to the public domain under CC0 1.0 Universal. Other pages on privacysafe.app/docs are CC BY-SA 4.0 unless the page says otherwise.