fix(web): harden config PATCH allowlists against prototype-chain keys
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -87,9 +87,10 @@ describe("config DELETE", () => {
|
||||
const before = await prisma.config.count();
|
||||
expect(before).toBeGreaterThan(0);
|
||||
|
||||
const res = await DELETE(delReq("__proto__"));
|
||||
expect(res.status).toBe(400);
|
||||
|
||||
for (const bad of ["__proto__", "constructor"]) {
|
||||
const res = await DELETE(delReq(bad));
|
||||
expect(res.status).toBe(400);
|
||||
}
|
||||
// Must not have collapsed to deleteMany({ where: {} }) and wiped the table.
|
||||
expect(await prisma.config.count()).toBe(before);
|
||||
expect(await prisma.config.findUnique({ where: { key: "qobuz.password" } })).not.toBeNull();
|
||||
|
||||
@@ -26,4 +26,11 @@ describe("discover config API", () => {
|
||||
expect(body["discover.chunkSize"]).toBe("25");
|
||||
expect(await prisma.config.findUnique({ where: { key: "nope" } })).toBeNull();
|
||||
});
|
||||
|
||||
it("ignores prototype-chain keys (__proto__, constructor) and writes no Config row", async () => {
|
||||
const before = await prisma.config.count();
|
||||
const res = await patch({ __proto__: "x", constructor: "y" });
|
||||
expect((await res.json()).updated).toBe(0);
|
||||
expect(await prisma.config.count()).toBe(before);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function PATCH(request: Request) {
|
||||
return Response.json({ error: "invalid JSON" }, { status: 400 });
|
||||
}
|
||||
const entries = Object.entries((body ?? {}) as Record<string, unknown>).filter(
|
||||
([k]) => k in DEFAULTS,
|
||||
([k]) => Object.prototype.hasOwnProperty.call(DEFAULTS, k),
|
||||
);
|
||||
for (const [key, value] of entries) {
|
||||
await prisma.config.upsert({
|
||||
|
||||
@@ -26,4 +26,11 @@ describe("monitor config API", () => {
|
||||
expect(body["monitor.pollIntervalHours"]).toBe("12");
|
||||
expect(await prisma.config.findUnique({ where: { key: "nope" } })).toBeNull();
|
||||
});
|
||||
|
||||
it("ignores prototype-chain keys (__proto__, constructor) and writes no Config row", async () => {
|
||||
const before = await prisma.config.count();
|
||||
const res = await patch({ __proto__: "x", constructor: "y" });
|
||||
expect((await res.json()).updated).toBe(0);
|
||||
expect(await prisma.config.count()).toBe(before);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function PATCH(request: Request) {
|
||||
return Response.json({ error: "invalid JSON" }, { status: 400 });
|
||||
}
|
||||
const entries = Object.entries((body ?? {}) as Record<string, unknown>).filter(
|
||||
([k]) => k in DEFAULTS,
|
||||
([k]) => Object.prototype.hasOwnProperty.call(DEFAULTS, k),
|
||||
);
|
||||
for (const [key, value] of entries) {
|
||||
await prisma.config.upsert({
|
||||
|
||||
Reference in New Issue
Block a user