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 }