Skip to content

Commit cccb0dc

Browse files
committed
fix: resolve PPTX file security issues
Bug 1: Extract workspaceId from file key using parseWorkspaceFileKey - handleLocalFile and handleCloudProxy now properly pass workspaceId - Previously passed undefined, causing getFileBase64 to fail with empty string Bug 2: Replace unsandboxed new Function with vm.createContext - User-provided code now runs in isolated VM context - Only pptx and getFileBase64 are exposed, blocking process/require access
1 parent 4a537ff commit cccb0dc

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

apps/sim/app/api/files/serve/[...path]/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
66
import { generatePptxFromCode } from '@/lib/copilot/tools/server/files/workspace-file'
77
import { CopilotFiles, isUsingCloudStorage } from '@/lib/uploads'
88
import type { StorageContext } from '@/lib/uploads/config'
9+
import { parseWorkspaceFileKey } from '@/lib/uploads/contexts/workspace/workspace-file-manager'
910
import { downloadFile } from '@/lib/uploads/core/storage-service'
1011
import { inferContextFromKey } from '@/lib/uploads/utils/file-utils'
1112
import { verifyFileAccess } from '@/app/api/files/authorization'
@@ -138,10 +139,11 @@ async function handleLocalFile(
138139
const rawBuffer = await readFile(filePath)
139140
const segment = filename.split('/').pop() || filename
140141
const displayName = stripStorageKeyPrefix(segment)
142+
const workspaceId = parseWorkspaceFileKey(filename)
141143
const { buffer: fileBuffer, contentType } = await compilePptxIfNeeded(
142144
rawBuffer,
143145
displayName,
144-
undefined,
146+
workspaceId || undefined,
145147
raw
146148
)
147149

@@ -202,10 +204,11 @@ async function handleCloudProxy(
202204

203205
const segment = cloudKey.split('/').pop() || 'download'
204206
const displayName = stripStorageKeyPrefix(segment)
207+
const workspaceId = parseWorkspaceFileKey(cloudKey)
205208
const { buffer: fileBuffer, contentType } = await compilePptxIfNeeded(
206209
rawBuffer,
207210
displayName,
208-
undefined,
211+
workspaceId || undefined,
209212
raw
210213
)
211214

apps/sim/lib/copilot/tools/server/files/workspace-file.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import vm from 'node:vm'
12
import { createLogger } from '@sim/logger'
23
import PptxGenJS from 'pptxgenjs'
34
import type { BaseServerTool, ServerToolContext } from '@/lib/copilot/tools/server/base-tool'
@@ -36,8 +37,19 @@ export async function generatePptxFromCode(code: string, workspaceId: string): P
3637
return `data:${mime};base64,${buffer.toString('base64')}`
3738
}
3839

39-
const fn = new Function('pptx', 'getFileBase64', `return (async () => { ${code} })()`)
40-
await fn(pptx, getFileBase64)
40+
const sandbox = {
41+
pptx,
42+
getFileBase64,
43+
__result: null as unknown,
44+
}
45+
46+
vm.createContext(sandbox)
47+
48+
const wrappedCode = `(async () => { ${code} })()`
49+
const script = new vm.Script(`__result = ${wrappedCode}`, { filename: 'pptx-code.js' })
50+
script.runInContext(sandbox)
51+
await sandbox.__result
52+
4153
const output = await pptx.write({ outputType: 'nodebuffer' })
4254
return output as Buffer
4355
}

0 commit comments

Comments
 (0)