fix(core): Don't reveal whether files exists if they're not within allowed paths (#18480)

This commit is contained in:
Jaakko Husso
2025-08-19 18:35:40 +03:00
committed by GitHub
parent 5df0ca908e
commit 970351bf23
2 changed files with 24 additions and 10 deletions

View File

@@ -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({});

View File

@@ -38,9 +38,8 @@ export async function isFilePathBlocked(filePath: string): Promise<boolean> {
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<boolean> {
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);
},