diff --git a/packages/core/src/execution-engine/node-execution-context/utils/__tests__/file-system-helper-functions.test.ts b/packages/core/src/execution-engine/node-execution-context/utils/__tests__/file-system-helper-functions.test.ts index 5b481ab779..e3c1e072e8 100644 --- a/packages/core/src/execution-engine/node-execution-context/utils/__tests__/file-system-helper-functions.test.ts +++ b/packages/core/src/execution-engine/node-execution-context/utils/__tests__/file-system-helper-functions.test.ts @@ -223,6 +223,19 @@ describe('getFileSystemHelperFunctions', () => { ); }); + it('should not reveal if file exists if it is within restricted path', async () => { + process.env[RESTRICT_FILE_ACCESS_TO] = '/allowed/path'; + + const error = new Error('ENOENT'); + // @ts-expect-error undefined property + error.code = 'ENOENT'; + (fsAccess as jest.Mock).mockRejectedValueOnce(error); + + await expect(helperFunctions.createReadStream('/blocked/path')).rejects.toThrow( + 'Access to the file is not allowed', + ); + }); + it('should create a read stream if file access is permitted', async () => { const filePath = '/allowed/path'; (fsAccess as jest.Mock).mockResolvedValueOnce({}); diff --git a/packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts b/packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts index 61943b1243..03cc0437f0 100644 --- a/packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts +++ b/packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts @@ -38,9 +38,8 @@ export async function isFilePathBlocked(filePath: string): Promise { let resolvedFilePath = ''; try { resolvedFilePath = await fsRealpath(filePath); - } catch (error) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (error.code === 'ENOENT') { + } catch (error: unknown) { + if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { resolvedFilePath = resolve(filePath); } else { throw error; @@ -64,6 +63,14 @@ export async function isFilePathBlocked(filePath: string): Promise { export const getFileSystemHelperFunctions = (node: INode): FileSystemHelperFunctions => ({ async createReadStream(filePath) { + if (await isFilePathBlocked(filePath.toString())) { + const allowedPaths = getAllowedPaths(); + const message = allowedPaths.length ? ` Allowed paths: ${allowedPaths.join(', ')}` : ''; + throw new NodeOperationError(node, `Access to the file is not allowed.${message}`, { + level: 'warning', + }); + } + try { await fsAccess(filePath); } catch (error) { @@ -76,13 +83,7 @@ export const getFileSystemHelperFunctions = (node: INode): FileSystemHelperFunct }) : error; } - if (await isFilePathBlocked(filePath as string)) { - const allowedPaths = getAllowedPaths(); - const message = allowedPaths.length ? ` Allowed paths: ${allowedPaths.join(', ')}` : ''; - throw new NodeOperationError(node, `Access to the file is not allowed.${message}`, { - level: 'warning', - }); - } + return createReadStream(filePath); },