fix(api): validate OpenAPI body size limits against Greptile findings

This commit is contained in:
Narciso 2026-08-11 14:57:42 -04:00
parent d11735d4cd
commit 8144e1a2fe
2 changed files with 28 additions and 13 deletions

View File

@ -16,17 +16,22 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return;
}
// getMultipartBody (trpc-openapi) doesn't accept maxBodySize, so multipart
// uploads have no cap unless enforced here before the handler reads the stream.
const contentLength = Number(req.headers["content-length"] ?? 0);
// getMultipartBody doesn't accept maxBodySize, so we cap it here instead.
const contentLength = Number(req.headers["content-length"]);
const isMultipart = req.headers["content-type"]?.startsWith(
"multipart/form-data",
);
if (isMultipart && !Number.isFinite(contentLength)) {
res.status(411).json({ message: "Content-Length required" });
return;
}
const limit = isMultipart
? OPENAPI_MAX_UPLOAD_SIZE
: OPENAPI_MAX_JSON_BODY_SIZE;
if (contentLength > limit) {
if (Number.isFinite(contentLength) && contentLength > limit) {
res.status(413).json({ message: "Payload too large" });
return;
}

View File

@ -14,16 +14,26 @@ export const DOKPLOY_DOCKER_PORT = process.env.DOKPLOY_DOCKER_PORT
export const CLEANUP_CRON_JOB = "50 23 * * *";
// Body size limits for the OpenAPI catch-all route (pages/api/[...trpc].ts).
// JSON/urlencoded bodies are capped by trpc-openapi's own default (100kb) unless
// we pass an explicit limit; multipart uploads (e.g. drop-deployment zips) have
// no built-in cap at all, so we enforce one manually via content-length.
export const OPENAPI_MAX_JSON_BODY_SIZE = process.env.OPENAPI_MAX_JSON_BODY_SIZE
? Number.parseInt(process.env.OPENAPI_MAX_JSON_BODY_SIZE, 10)
: 10 * 1024 * 1024; // 10mb
const parseByteSize = (envVar: string, fallback: number): number => {
const raw = process.env[envVar];
if (!raw) return fallback;
const parsed = Number.parseInt(raw, 10);
if (!Number.isFinite(parsed) || parsed <= 0) {
console.warn(`Invalid ${envVar}="${raw}", using default ${fallback}`);
return fallback;
}
return parsed;
};
export const OPENAPI_MAX_UPLOAD_SIZE = process.env.OPENAPI_MAX_UPLOAD_SIZE
? Number.parseInt(process.env.OPENAPI_MAX_UPLOAD_SIZE, 10)
: 1024 * 1024 * 1024; // 1gb
export const OPENAPI_MAX_JSON_BODY_SIZE = parseByteSize(
"OPENAPI_MAX_JSON_BODY_SIZE",
10 * 1024 * 1024, // 10mb
);
export const OPENAPI_MAX_UPLOAD_SIZE = parseByteSize(
"OPENAPI_MAX_UPLOAD_SIZE",
1024 * 1024 * 1024, // 1gb
);
type DockerSocketCandidate = {
label: string;