Files
James Anderson a0f4e26655 fix(security): honor pages API bodyParser config (F-PROD-4) (#1617)
* fix(security): honor pages API bodyParser config (F-PROD-4)

Pages Router API routes export configuration like:

    export const config = { api: { bodyParser: false } };
    export const config = { api: { bodyParser: { sizeLimit: '4mb' } } };

vinext silently ignored this, hard-coding a 1 MB limit and always
parsing the body. That created a security downgrade for webhook
handlers (Stripe, GitHub, Slack, etc.) that depend on
'bodyParser: false' to read the raw request stream for HMAC
signature verification. By the time the user handler ran, the body
had already been consumed and parsed into 'req.body', so HMAC
verification would either fail closed (no signature match) or fail
open (handlers that fall back to an empty body for unsupported
content types).

Legitimate large uploads were also rejected with 413 even when the
route declared 'sizeLimit: "4mb"' or higher.

This change introduces a shared helper that resolves the route
module's 'config.api.bodyParser' option and patches both code paths:

  - Node/dev path:   packages/vinext/src/server/api-handler.ts
  - Workers/prod:    packages/vinext/src/server/pages-api-route.ts
                     (+ packages/vinext/src/server/pages-node-compat.ts)

Behaviour now matches Next.js
(packages/next/src/server/api-utils/node/api-resolver.ts):

  - bodyParser: false               -> skip parsing entirely. Node
                                       handlers receive the raw
                                       IncomingMessage stream;
                                       Workers handlers receive
                                       request.body as a
                                       ReadableStream<Uint8Array>
                                       on 'req.body'.
  - bodyParser: { sizeLimit: '4mb' } -> parse with the user-supplied
                                        limit instead of the
                                        hard-coded 1 MB.
  - bodyParser: true / undefined     -> existing 1 MB default behaviour.

The sizeLimit parser accepts the same suffix grammar Next.js does
('500b', '100kb', '4mb', '1gb'), implemented inline rather than
pulling the 'bytes' package.

Tests cover both Node and Workers paths plus parser-level unit
tests, including:

  - bodyParser: false leaves the stream intact for HMAC verification
  - sizeLimit '4mb' accepts a 2 MB POST that used to 413
  - sizeLimit '4mb' rejects a 5 MB POST with 413
  - sizeLimit '100kb' rejects a 200 KB POST with 413
  - No config preserves the 1 MB default

config.api.responseLimit is not in scope for this PR and remains a
follow-up.

Reference: Finding F-PROD-4 in SECURITY-AUDIT-2026-05.md

* chore(security): drop unused ResolvedBodyParserConfig export to satisfy knip
2026-05-27 16:25:32 +01:00
..
2026-02-24 09:29:39 -06:00

vinext

This file is overwritten from the repo root README.md during prepack. Edit the root README.md instead.