fix(backend): validate context key element types

Reject booleans, nulls, and nested arrays in the key
param. Only string, number, and plain objects with
primitive values are accepted.

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2026-03-12 01:55:39 +00:00
parent f0e1953409
commit b06adb8609
2 changed files with 34 additions and 1 deletions

View File

@@ -204,6 +204,26 @@ describe("GET /api/context", () => {
expect(body.error).toContain("key") expect(body.error).toContain("key")
}) })
test("returns 400 when key contains invalid element types", async () => {
const { app } = buildContextApp("user-1")
const res = await app.request("/api/context?key=[true,null,[1,2]]")
expect(res.status).toBe(400)
const body = (await res.json()) as { error: string }
expect(body.error).toContain("key")
})
test("returns 400 when key is an empty array", async () => {
const { app } = buildContextApp("user-1")
const res = await app.request("/api/context?key=[]")
expect(res.status).toBe(400)
const body = (await res.json()) as { error: string }
expect(body.error).toContain("key")
})
test("returns 400 when match param is invalid", async () => { test("returns 400 when match param is invalid", async () => {
const { app } = buildContextApp("user-1") const { app } = buildContextApp("user-1")

View File

@@ -59,7 +59,7 @@ function handleGetContext(c: Context<Env>) {
return c.json({ error: 'Invalid or missing "key" parameter: must be a JSON array' }, 400) return c.json({ error: 'Invalid or missing "key" parameter: must be a JSON array' }, 400)
} }
if (!Array.isArray(parsed)) { if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every(isContextKeyPart)) {
return c.json({ error: 'Invalid or missing "key" parameter: must be a JSON array' }, 400) return c.json({ error: 'Invalid or missing "key" parameter: must be a JSON array' }, 400)
} }
@@ -103,3 +103,16 @@ function handleGetContext(c: Context<Env>) {
return c.json({ match: "prefix", entries }) return c.json({ match: "prefix", entries })
} }
/** Validates that a value is a valid ContextKeyPart (string, number, or plain object of primitives). */
function isContextKeyPart(value: unknown): boolean {
if (typeof value === "string" || typeof value === "number") {
return true
}
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
return Object.values(value).every(
(v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean",
)
}
return false
}