Security fixes pass #1

This commit is contained in:
Benjamin Toby 2026-04-19 14:59:20 +01:00
parent cb5126c947
commit 3b26292124
3 changed files with 47 additions and 11 deletions

1
.gitignore vendored
View File

@ -182,3 +182,4 @@ __fixtures__
/.dump
/.vscode
/source.md
SECURITY.md

View File

@ -68,16 +68,16 @@ export default async function ({ req }: Params): Promise<Response> {
const config = module.config as BunextServerRouteConfig | undefined;
const maxBodyBytes = config?.max_request_body_mb
? config.max_request_body_mb * MBInBytes
: ServerDefaultRequestBodyLimitBytes;
const contentLength = req.headers.get("content-length");
if (contentLength) {
const size = parseInt(contentLength, 10);
if (
(config?.max_request_body_mb &&
size > config.max_request_body_mb * MBInBytes) ||
size > ServerDefaultRequestBodyLimitBytes
) {
if (size > maxBodyBytes) {
return Response.json(
{
success: false,
@ -91,6 +91,26 @@ export default async function ({ req }: Params): Promise<Response> {
},
);
}
} 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",
},
},
);
}
routeParams.body = JSON.parse(
new TextDecoder().decode(body) || "{}",
);
}
const target_module = (module["default"] ||

View File

@ -1,8 +1,18 @@
import EJSON from "./ejson";
/**
* # Convert Serialized Query back to object
*/
const DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
function sanitize<T>(value: T): T {
if (value === null || typeof value !== "object") return value;
if (Array.isArray(value)) return value.map(sanitize) as T;
const clean: Record<string, any> = Object.create(null);
for (const key of Object.keys(value as Record<string, any>)) {
if (DANGEROUS_KEYS.has(key)) continue;
clean[key] = sanitize((value as Record<string, any>)[key]);
}
return clean as T;
}
export default function deserializeQuery(
query: string | { [s: string]: any }
): {
@ -17,12 +27,17 @@ export default function deserializeQuery(
const key = keys[i];
const value = queryObject[key];
if (DANGEROUS_KEYS.has(key)) {
delete queryObject[key];
continue;
}
if (typeof value == "string") {
if (value.match(/^\{|^\[/)) {
queryObject[key] = EJSON.parse(value);
queryObject[key] = sanitize(EJSON.parse(value));
}
}
}
return queryObject;
return sanitize(queryObject);
}