mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-20 03:12:15 +00:00
fix(core): Don't reveal whether files exists if they're not within allowed paths (#18480)
This commit is contained in:
@@ -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 () => {
|
it('should create a read stream if file access is permitted', async () => {
|
||||||
const filePath = '/allowed/path';
|
const filePath = '/allowed/path';
|
||||||
(fsAccess as jest.Mock).mockResolvedValueOnce({});
|
(fsAccess as jest.Mock).mockResolvedValueOnce({});
|
||||||
|
|||||||
@@ -38,9 +38,8 @@ export async function isFilePathBlocked(filePath: string): Promise<boolean> {
|
|||||||
let resolvedFilePath = '';
|
let resolvedFilePath = '';
|
||||||
try {
|
try {
|
||||||
resolvedFilePath = await fsRealpath(filePath);
|
resolvedFilePath = await fsRealpath(filePath);
|
||||||
} catch (error) {
|
} catch (error: unknown) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
||||||
if (error.code === 'ENOENT') {
|
|
||||||
resolvedFilePath = resolve(filePath);
|
resolvedFilePath = resolve(filePath);
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
throw error;
|
||||||
@@ -64,6 +63,14 @@ export async function isFilePathBlocked(filePath: string): Promise<boolean> {
|
|||||||
|
|
||||||
export const getFileSystemHelperFunctions = (node: INode): FileSystemHelperFunctions => ({
|
export const getFileSystemHelperFunctions = (node: INode): FileSystemHelperFunctions => ({
|
||||||
async createReadStream(filePath) {
|
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 {
|
try {
|
||||||
await fsAccess(filePath);
|
await fsAccess(filePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -76,13 +83,7 @@ export const getFileSystemHelperFunctions = (node: INode): FileSystemHelperFunct
|
|||||||
})
|
})
|
||||||
: error;
|
: 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);
|
return createReadStream(filePath);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user