From 8a8e95a39bdc5acce049ab2ccf8160821b2c6104 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Fri, 7 Aug 2026 17:29:58 +0900 Subject: [PATCH] fix(management): reject null Claude toggle body --- src/server/management/native-integration-routes.ts | 2 +- tests/native-claude-code-toggle.test.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/server/management/native-integration-routes.ts b/src/server/management/native-integration-routes.ts index 72d0098ec..77d1d77d0 100644 --- a/src/server/management/native-integration-routes.ts +++ b/src/server/management/native-integration-routes.ts @@ -523,7 +523,7 @@ export async function handleNativeIntegrationRoutes(ctx: ManagementContext): Pro rethrowManagementBodyTooLarge(error); return jsonResponse({ error: "invalid JSON body" }, 400); } - if (typeof body.enabled !== "boolean") { + if (!body || typeof body !== "object" || Array.isArray(body) || typeof body.enabled !== "boolean") { return jsonResponse({ error: "enabled must be a boolean" }, 400); } diff --git a/tests/native-claude-code-toggle.test.ts b/tests/native-claude-code-toggle.test.ts index d6f0777ce..59ad138bf 100644 --- a/tests/native-claude-code-toggle.test.ts +++ b/tests/native-claude-code-toggle.test.ts @@ -117,6 +117,17 @@ test("a non-boolean enabled is rejected", async () => { expect(res!.status).toBe(400); }); +test("a null body is rejected instead of crashing the route", async () => { + const { response } = dispatch(baseConfig(), "/api/native-integrations/claude", { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: "null", + }); + const res = await response; + expect(res!.status).toBe(400); + expect(await res!.json()).toEqual({ error: "enabled must be a boolean" }); +}); + test("genuine lock contention refuses 409 config_busy, a broken lock is a 500", async () => { /* * `ConfigMutationLockError` wraps EVERY acquisition failure behind one