From af2071c60cee190afd0dd2e1198ccdb9b098c347 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 7 Oct 2024 16:44:28 +0100 Subject: [PATCH 1/8] fixing vulns for ent client --- hosting/proxy/nginx.prod.conf | 2 +- .../controllers/static/templates/preview.hbs | 2 +- packages/server/src/environment.ts | 1 + .../src/sdk/app/rows/tests/utils.spec.ts | 41 +++++++++++++++++++ packages/server/src/sdk/app/rows/utils.ts | 10 +++++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/hosting/proxy/nginx.prod.conf b/hosting/proxy/nginx.prod.conf index 59722dac5c..6d5db51bce 100644 --- a/hosting/proxy/nginx.prod.conf +++ b/hosting/proxy/nginx.prod.conf @@ -51,7 +51,7 @@ http { proxy_buffering off; set $csp_default "default-src 'self'"; - set $csp_script "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.budibase.net https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io https://d2l5prqdbvm3op.cloudfront.net https://us-assets.i.posthog.com"; + set $csp_script "script-src 'self' 'nonce-builderPreview' unsafe-eval' https://*.budibase.net https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io https://d2l5prqdbvm3op.cloudfront.net https://us-assets.i.posthog.com"; set $csp_style "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com"; set $csp_object "object-src 'none'"; set $csp_base_uri "base-uri 'self'"; diff --git a/packages/server/src/api/controllers/static/templates/preview.hbs b/packages/server/src/api/controllers/static/templates/preview.hbs index 54b5b1a4e4..be38825ec9 100644 --- a/packages/server/src/api/controllers/static/templates/preview.hbs +++ b/packages/server/src/api/controllers/static/templates/preview.hbs @@ -31,7 +31,7 @@ } - ", + "\">", + "", + "
Hover over me!
", + "'; EXEC sp_msforeachtable 'DROP TABLE ?'; --", + "{alert('Injected')}", + "UNION SELECT * FROM users", + "INSERT INTO users (username, password) VALUES ('admin', 'password')", + "/* This is a comment */ SELECT * FROM users", + "" + ])('test potentially unsafe input: %s', async input => { + environment.XSS_SAFE_MODE = true + const table = getTable() + const row = { text: input } + const output = await validate({ source: table, row }) + expect(output.valid).toBe(false) + expect(output.errors).toBe(["Input not sanitised - potentially vulnerable to XSS"]) + environment.XSS_SAFE_MODE = false + }) + }) }) diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index 6ef4dcbc8e..4c02889f8f 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -22,6 +22,7 @@ import { extractViewInfoFromID, isRelationshipColumn } from "../../../db/utils" import { isSQL } from "../../../integrations/utils" import { docIds, sql } from "@budibase/backend-core" import { getTableFromSource } from "../../../api/controllers/row/utils" +import env from "../../../environment" const SQL_CLIENT_SOURCE_MAP: Record = { [SourceName.POSTGRES]: SqlClient.POSTGRES, @@ -43,6 +44,8 @@ const SQL_CLIENT_SOURCE_MAP: Record = { [SourceName.BUDIBASE]: undefined, } +const XSS_INPUT_REGEX = /[<>;"'(){}]|--|\/\*|\*\/|union|select|insert|drop|delete|update|exec|script/i + export function getSQLClient(datasource: Datasource): SqlClient { if (!isSQL(datasource)) { throw new Error("Cannot get SQL Client for non-SQL datasource") @@ -222,6 +225,13 @@ export async function validate({ } else { res = validateJs.single(row[fieldName], constraints) } + + if (env.XSS_SAFE_MODE && typeof row[fieldName] === "string") { + if (XSS_INPUT_REGEX.test(row[fieldName])) { + errors[fieldName] = ['Input not sanitised - potentially vulnerable to XSS'] + } + } + if (res) errors[fieldName] = res } return { valid: Object.keys(errors).length === 0, errors } From ce61af1331ebaf6034b05af69afffba9f121c08e Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 7 Oct 2024 16:47:49 +0100 Subject: [PATCH 2/8] XSS safe mode to prevent unsanitised input --- packages/server/src/sdk/app/rows/tests/utils.spec.ts | 10 ++++++---- packages/server/src/sdk/app/rows/utils.ts | 7 +++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/server/src/sdk/app/rows/tests/utils.spec.ts b/packages/server/src/sdk/app/rows/tests/utils.spec.ts index cd25880a85..9b7711993e 100644 --- a/packages/server/src/sdk/app/rows/tests/utils.spec.ts +++ b/packages/server/src/sdk/app/rows/tests/utils.spec.ts @@ -354,7 +354,7 @@ describe("validate", () => { "1' OR '1' = '1", "' OR 'a' = 'a", "", - "\">", + '">', "", "
Hover over me!
", "'; EXEC sp_msforeachtable 'DROP TABLE ?'; --", @@ -362,14 +362,16 @@ describe("validate", () => { "UNION SELECT * FROM users", "INSERT INTO users (username, password) VALUES ('admin', 'password')", "/* This is a comment */ SELECT * FROM users", - "" - ])('test potentially unsafe input: %s', async input => { + '', + ])("test potentially unsafe input: %s", async input => { environment.XSS_SAFE_MODE = true const table = getTable() const row = { text: input } const output = await validate({ source: table, row }) expect(output.valid).toBe(false) - expect(output.errors).toBe(["Input not sanitised - potentially vulnerable to XSS"]) + expect(output.errors).toBe([ + "Input not sanitised - potentially vulnerable to XSS", + ]) environment.XSS_SAFE_MODE = false }) }) diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index 4c02889f8f..bded6a7a18 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -44,7 +44,8 @@ const SQL_CLIENT_SOURCE_MAP: Record = { [SourceName.BUDIBASE]: undefined, } -const XSS_INPUT_REGEX = /[<>;"'(){}]|--|\/\*|\*\/|union|select|insert|drop|delete|update|exec|script/i +const XSS_INPUT_REGEX = + /[<>;"'(){}]|--|\/\*|\*\/|union|select|insert|drop|delete|update|exec|script/i export function getSQLClient(datasource: Datasource): SqlClient { if (!isSQL(datasource)) { @@ -228,7 +229,9 @@ export async function validate({ if (env.XSS_SAFE_MODE && typeof row[fieldName] === "string") { if (XSS_INPUT_REGEX.test(row[fieldName])) { - errors[fieldName] = ['Input not sanitised - potentially vulnerable to XSS'] + errors[fieldName] = [ + "Input not sanitised - potentially vulnerable to XSS", + ] } } From 12fdb930aa005a30e0f03999e718a27e2e3d80de Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 7 Oct 2024 17:31:45 +0100 Subject: [PATCH 3/8] remove nonce --- .../server/src/api/controllers/static/templates/preview.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/static/templates/preview.hbs b/packages/server/src/api/controllers/static/templates/preview.hbs index be38825ec9..54b5b1a4e4 100644 --- a/packages/server/src/api/controllers/static/templates/preview.hbs +++ b/packages/server/src/api/controllers/static/templates/preview.hbs @@ -31,7 +31,7 @@ } -