diff --git a/packages/server/src/api/controllers/query/index.ts b/packages/server/src/api/controllers/query/index.ts index 3c21537484..0dba20dacd 100644 --- a/packages/server/src/api/controllers/query/index.ts +++ b/packages/server/src/api/controllers/query/index.ts @@ -14,22 +14,35 @@ import { SessionCookie, JsonFieldSubType, QueryResponse, - QueryPreview, QuerySchema, FieldType, ExecuteQueryRequest, ExecuteQueryResponse, - Row, QueryParameter, PreviewQueryRequest, PreviewQueryResponse, } from "@budibase/types" import { ValidQueryNameRegex, utils as JsonUtils } from "@budibase/shared-core" +import { findHBSBlocks } from "@budibase/string-templates" const Runner = new Thread(ThreadType.QUERY, { timeoutMs: env.QUERY_THREAD_TIMEOUT, }) +function validateQueryInputs(parameters: Record) { + for (let entry of Object.entries(parameters)) { + const [key, value] = entry + if (typeof value !== "string") { + continue + } + if (findHBSBlocks(value).length !== 0) { + throw new Error( + `Parameter '${key}' input contains a handlebars binding - this is not allowed.` + ) + } + } +} + export async function fetch(ctx: UserCtx) { ctx.body = await sdk.queries.fetch() } @@ -123,10 +136,10 @@ function getAuthConfig(ctx: UserCtx) { function enrichParameters( queryParameters: QueryParameter[], - requestParameters: { [key: string]: string } = {} -): { - [key: string]: string -} { + requestParameters: Record = {} +): Record { + // first check parameters are all valid + validateQueryInputs(requestParameters) // make sure parameters are fully enriched with defaults for (let parameter of queryParameters) { if (!requestParameters[parameter.name]) { diff --git a/packages/server/src/api/routes/tests/queries/query.seq.spec.ts b/packages/server/src/api/routes/tests/queries/query.seq.spec.ts index 4347ed9044..fc90ad4247 100644 --- a/packages/server/src/api/routes/tests/queries/query.seq.spec.ts +++ b/packages/server/src/api/routes/tests/queries/query.seq.spec.ts @@ -408,6 +408,21 @@ describe("/queries", () => { }, }) }) + + it("shouldn't allow handlebars to be passed as parameters", async () => { + const res = await request + .post(`/api/queries/${query._id}`) + .send({ + parameters: { + a: "{{ 'test' }}", + }, + }) + .set(config.defaultHeaders()) + .expect(400) + expect(res.body.message).toEqual( + "Parameter 'a' input contains a handlebars binding - this is not allowed." + ) + }) }) describe("variables", () => { diff --git a/packages/types/src/api/web/query.ts b/packages/types/src/api/web/query.ts index 3959cdea19..66f0248647 100644 --- a/packages/types/src/api/web/query.ts +++ b/packages/types/src/api/web/query.ts @@ -11,7 +11,7 @@ export interface PreviewQueryResponse { } export interface ExecuteQueryRequest { - parameters?: { [key: string]: string } + parameters?: Record pagination?: any }