← HomeBlog

2026-10-06 · Application security

Next.js RCE vulnerability: why manual testing finds what scanners miss

Vercel shipped an emergency patch for Next.js on August 25, 2026, covering two critical, unauthenticated remote code execution flaws. One traces to a heap buffer overflow in libheif, the AVIF decoding library that Next.js reaches through sharp (tracked as GHSA-2xp9-vwfh-vxw4, no CVE assigned yet, CVSS 9.5). The other is a Windows-only path traversal bug in the incremental cache, tracked as CVE-2026-75604, CVSS 9.0.

Both flaws allowed unauthenticated code execution on widely deployed production systems, and both would have sailed past most automated scanners without triggering a single alert. That's exactly why we push back when SaaS founders ask if they can run a scanner instead of a manual penetration test. This pair of bugs shows three blind spots in automated testing that only manual expertise catches.


Image processing: the scanner's blind spot

The AVIF vulnerability exploited a heap buffer overflow in HeifPixelImage::scale_nearest_neighbor(), inside libheif versions 1.23.1 and earlier. Next.js's built-in Image Optimization API uses sharp for resizing, sharp uses libvips, and libvips links against libheif to decode AVIF and HEIC files. An attacker who submits a crafted AVIF file to a Next.js image optimization endpoint gets arbitrary code execution on the server, with no login required.

A scanner hitting an image upload endpoint checks whether it accepts POST requests, whether there's rate limiting, and whether common image formats come back with a 200. It has no way to see which image processing library the application uses, how many layers deep the dependency chain goes (Next.js to sharp to libvips to libheif), whether processing runs synchronously in the request path, or what privileges that code executes with.

During manual testing, we trace that whole chain. We upload test images and watch how the application handles them, check response times to catch synchronous processing, read the JavaScript bundle to identify which image libraries are in play, and test whether processed images get cached and reused across sessions. When we find an image upload endpoint in a Next.js app, we specifically test AVIF handling, because we know Next.js reaches libheif through sharp. We craft malformed images with oversized headers, corrupted metadata, and boundary condition violations, then check whether the app validates dimensions before processing and whether a processing timeout even exists. None of that is something a scanner can automate. It requires understanding how the framework's image pipeline is wired and where the trust boundary actually sits.


Windows path traversal: a bug that only exists on one OS

The second flaw, CVE-2026-75604, is more revealing. It lives in FileSystemCache.getFilePath, and it only affects Next.js apps using both the Pages Router and App Router without Cache Components, running on a Windows filesystem. Linux and macOS deployments aren't affected at all, because the vulnerability comes from a failure to sanitize backslashes, the path separator on Windows, while forward slashes on Linux were handled correctly.

Scanners can't catch this class of bug for three reasons. They don't know what operating system your application runs on, so a generic path traversal payload tells you nothing about whether it's exploitable in your specific deployment. They don't understand framework-specific routing logic. Next.js has multiple router systems with different security characteristics, and this bug only hits one particular combination of them. And they can't test OS-specific filesystem behavior: Windows handles path separators, drive letters, and UNC paths differently than Unix, and that difference is exactly what this vulnerability exploits.

During our penetration tests, we ask clients about their deployment environment up front. When we test a Next.js app running on Windows (rare, but it shows up in enterprises still running IIS), we adjust the methodology: backslash handling, drive letter abuse, UNC path injection, case-insensitivity exploitation. We also map every available route, identify which router system is active, and check whether Cache Components are enabled, because that contextual knowledge is what tells us which tests are even relevant.


The dependency chain problem

Both vulnerabilities land on the same underlying issue: the dependency chain problem. Next.js depends on sharp. Sharp depends on libvips. Libvips depends on libheif. Libheif had a heap buffer overflow. The exploitable code sat three layers deep in the tree, in a library most application security reviews never look at directly.

No scanner reliably maps your full dependency tree, flags which dependencies handle untrusted input, and surfaces exploitability in that specific context. Even software composition analysis tools mostly tell you "you have a vulnerable dependency." They don't tell you whether that dependency is reachable with attacker-controlled input in your application.

During manual testing, we trace data flow through dependencies rather than stopping at the endpoint. When we find an image upload path, we research the entire processing pipeline behind it: which libraries are in use, whether they're current, and what's been disclosed against them recently. We also test the boundary between application code and third-party libraries directly. Does the app validate input before handing it to the library? Are there size limits, timeouts, or error handling that might leak information about the pipeline underneath?


What manual testing catches that scanners miss

Here's a short list of what we routinely find in Next.js penetration tests that scanners never flag: server-side request forgery in API routes that fetch external resources without validation, authentication bypass through middleware misconfiguration that accidentally exposes a protected route, Server Component leaks where sensitive data ends up serialized into the client-side bundle, image optimization abuse that causes resource exhaustion through images that force excessive processing, and static generation issues where build-time data fetching exposes credentials or internal resources.

All five are framework-specific and context-dependent. They require understanding how Next.js works, how your particular app uses its features, and where the actual security boundary sits, not just what a generic payload returns.


Practical steps for SaaS CTOs running Next.js

Upgrade to Next.js 15.5.24 or 16.3.3 now. Both patches disable AVIF optimization until the upstream libheif fix propagates, and there's no workaround for the Windows path traversal bug short of upgrading.

Audit your image processing pipeline: which libraries handle uploads, whether you validate images before processing, and whether size limits exist. Check your deployment environment, since Windows-hosted Next.js needs different scrutiny than Linux. Map your dependency tree so you know which libraries touch untrusted input and can watch them for new disclosures. And test framework-specific surfaces directly. Server Components, API routes, middleware, and image optimization each carry their own security implications that a generic scan won't surface.

Automated scanners are useful for known vulnerabilities and common misconfigurations. They miss the context-dependent, framework-specific bugs that actually get exploited, which is what both of these Next.js flaws were.


At Faultline Security, we run web application penetration tests for European B2B SaaS startups, following PTES and OWASP WSTG methodology, with findings that satisfy SOC 2 Type II and ISO 27001 requirements. Fixed pricing runs EUR 3,000 to EUR 7,000, with a 3 to 10 business day turnaround by tier. If you're running Next.js in production and want the vulnerabilities scanners miss found before an attacker does, get in touch.