Fix security vulnerabilities

This commit is contained in:
2026-10-13 15:52:34 +01:00
parent 74103a19c9
commit eefb2ea5d2
46 changed files with 375 additions and 403 deletions
+43 -47
View File
@@ -7,6 +7,7 @@ import _ from "lodash";
import path from "path";
import grabDirNames from "../../utils/grab-dir-names";
import grabRelativePath from "../../utils/grab-relative-path";
import { RequestBodyTooLargeError } from "../../utils/read-request-body";
const { ROOT_DIR } = grabDirNames();
export default async function ({ req }) {
try {
@@ -27,10 +28,6 @@ export default async function ({ req }) {
},
});
}
const routeParams = await grabRouteParams({
req,
query: match.query,
});
let module;
const now = Date.now();
const relative_match_path = grabRelativePath(match.filePath);
@@ -50,54 +47,37 @@ export default async function ({ req }) {
? config.max_request_body_mb * MBInBytes
: ServerDefaultRequestBodyLimitBytes;
const contentLength = req.headers.get("content-length");
if (contentLength) {
const size = parseInt(contentLength, 10);
if (size > maxBodyBytes) {
return Response.json({
success: false,
msg: "Request Body Too Large!",
}, {
status: 413,
headers: {
"Content-Type": "application/json",
},
});
}
if (contentLength && parseInt(contentLength, 10) > maxBodyBytes) {
return bodyTooLargeResponse();
}
else if (req.method !== "GET" && req.method !== "HEAD") {
const body = await req.arrayBuffer();
if (body.byteLength > maxBodyBytes) {
return Response.json({
success: false,
msg: "Request Body Too Large!",
}, {
status: 413,
headers: {
"Content-Type": "application/json",
},
});
}
try {
routeParams.body = JSON.parse(new TextDecoder().decode(body) || "{}");
}
catch (error) {
log.error(`Invalid JSON body for ${url.pathname}: ${error?.message}`);
return Response.json({
success: false,
msg: "Invalid JSON body",
}, {
status: 400,
headers: {
"Content-Type": "application/json",
},
});
let routeParams;
try {
routeParams = await grabRouteParams({
req,
query: match.query,
max_body_bytes: maxBodyBytes,
});
}
catch (error) {
if (error instanceof RequestBodyTooLargeError) {
return bodyTooLargeResponse();
}
throw error;
}
const target_module = (module["default"] ||
module["handler"]);
if (typeof target_module !== "function") {
log.error(`API Route ${url.pathname} has no default or \`handler\` export`);
return Response.json({
success: false,
msg: is_dev
? `Route ${url.pathname} has no default or \`handler\` export`
: "Internal Server Error",
}, { status: 500 });
}
let res;
try {
res = await target_module?.({
res = await target_module({
...routeParams,
});
}
@@ -105,7 +85,7 @@ export default async function ({ req }) {
log.error(`API Route Error (${url.pathname}): ${error?.message}\n${error?.stack || ""}`);
return Response.json({
success: false,
msg: `Route handler error: ${error?.message || "Internal Server Error"}`,
msg: routeErrorMessage(error),
}, {
status: 500,
headers: {
@@ -138,7 +118,7 @@ export default async function ({ req }) {
log.error(`API Route Error (${url.pathname}): ${error?.message}\n${error?.stack || ""}`);
return Response.json({
success: false,
msg: `Route handler error: ${error?.message || "Internal Server Error"}`,
msg: routeErrorMessage(error),
}, {
status: 500,
headers: {
@@ -147,3 +127,19 @@ export default async function ({ req }) {
});
}
}
function bodyTooLargeResponse() {
return Response.json({
success: false,
msg: "Request Body Too Large!",
}, { status: 413 });
}
/**
* Error details can leak internals, so they are only exposed in
* development. They are always logged server-side.
*/
function routeErrorMessage(error) {
if (!isDevelopment()) {
return "Internal Server Error";
}
return `Route handler error: ${error?.message || "Internal Server Error"}`;
}