diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 544bde1fbb..4c5415a6c6 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -1,4 +1,4 @@ -import { ValidFileExtensions } from "@budibase/shared-core" +import { InvalidFileExtensions } from "@budibase/shared-core" require("svelte/register") @@ -86,7 +86,10 @@ export const uploadFile = async function ( ) } - if (!env.SELF_HOSTED && !ValidFileExtensions.includes(extension)) { + if ( + !env.SELF_HOSTED && + InvalidFileExtensions.includes(extension.toLowerCase()) + ) { throw new BadRequestError( `File "${file.name}" has an invalid extension: "${extension}"` ) diff --git a/packages/server/src/api/routes/tests/attachment.spec.ts b/packages/server/src/api/routes/tests/attachment.spec.ts index 14d2e845f6..e230b0688a 100644 --- a/packages/server/src/api/routes/tests/attachment.spec.ts +++ b/packages/server/src/api/routes/tests/attachment.spec.ts @@ -35,6 +35,17 @@ describe("/api/applications/:appId/sync", () => { }) }) + it("should reject an upload with a malicious uppercase file extension", async () => { + await config.withEnv({ SELF_HOSTED: undefined }, async () => { + let resp = (await config.api.attachment.process( + "OHNO.EXE", + Buffer.from([0]), + { expectStatus: 400 } + )) as unknown as APIError + expect(resp.message).toContain("invalid extension") + }) + }) + it("should reject an upload with no file", async () => { let resp = (await config.api.attachment.process( undefined as any, diff --git a/packages/shared-core/src/constants.ts b/packages/shared-core/src/constants.ts index e7c6feb20a..0787b8bed1 100644 --- a/packages/shared-core/src/constants.ts +++ b/packages/shared-core/src/constants.ts @@ -96,45 +96,61 @@ export enum BuilderSocketEvent { export const SocketSessionTTL = 60 export const ValidQueryNameRegex = /^[^()]*$/ export const ValidColumnNameRegex = /^[_a-zA-Z0-9\s]*$/g -export const ValidFileExtensions = [ - "avif", - "css", - "csv", - "docx", - "drawio", - "editorconfig", - "edl", - "enc", - "export", - "geojson", - "gif", - "htm", - "html", - "ics", - "iqy", - "jfif", - "jpeg", - "jpg", - "json", - "log", - "md", - "mid", - "odt", - "pdf", - "png", - "ris", - "rtf", - "svg", - "tex", - "toml", - "twig", - "txt", - "url", - "wav", - "webp", - "xls", - "xlsx", - "xml", - "yaml", - "yml", + +export const InvalidFileExtensions = [ + "7z", + "action", + "apk", + "app", + "bat", + "bin", + "cab", + "cmd", + "com", + "command", + "cpl", + "csh", + "ex_", + "exe", + "gadget", + "inf1", + "ins", + "inx", + "ipa", + "isu", + "job", + "js", + "jse", + "ksh", + "lnk", + "msc", + "msi", + "msp", + "mst", + "osx", + "out", + "paf", + "php", + "pif", + "prg", + "ps1", + "reg", + "rgs", + "run", + "scr", + "sct", + "shb", + "shs", + "tar", + "u3p", + "vb", + "vbe", + "vbs", + "vbscript", + "wasm", + "workflow", + "ws", + "wsf", + "wsh", + "zip", ]