fix(core): Prevent DoS via malformed binary data ID (#16229)

This commit is contained in:
Iván Ovejero
2025-06-13 12:53:00 +02:00
committed by GitHub
parent 7177e3aab0
commit 43c52a8b4f
2 changed files with 32 additions and 5 deletions

View File

@@ -26,7 +26,7 @@ describe('BinaryDataController', () => {
await controller.get(request, response, query); await controller.get(request, response, query);
expect(response.status).toHaveBeenCalledWith(400); expect(response.status).toHaveBeenCalledWith(400);
expect(response.end).toHaveBeenCalledWith('Missing binary data mode'); expect(response.end).toHaveBeenCalledWith('Malformed binary data ID');
}); });
it('should return 400 if binary data mode is invalid', async () => { it('should return 400 if binary data mode is invalid', async () => {
@@ -152,6 +152,24 @@ describe('BinaryDataController', () => {
expect(result).toBe(stream); expect(result).toBe(stream);
expect(binaryDataService.getAsStream).toHaveBeenCalledWith('filesystem:123'); expect(binaryDataService.getAsStream).toHaveBeenCalledWith('filesystem:123');
}); });
describe('with malicious binary data IDs', () => {
it.each([
['filesystem:'],
['filesystem-v2:'],
['filesystem:/'],
['filesystem-v2:/'],
['filesystem://'],
['filesystem-v2://'],
])('should return 400 for ID "%s"', async (maliciousId) => {
const query = { id: maliciousId, action: 'download' } as BinaryDataQueryDto;
await controller.get(request, response, query);
expect(response.status).toHaveBeenCalledWith(400);
expect(response.end).toHaveBeenCalledWith('Malformed binary data ID');
});
});
}); });
describe('getSigned', () => { describe('getSigned', () => {
@@ -162,7 +180,7 @@ describe('BinaryDataController', () => {
await controller.getSigned(request, response, query); await controller.getSigned(request, response, query);
expect(response.status).toHaveBeenCalledWith(400); expect(response.status).toHaveBeenCalledWith(400);
expect(response.end).toHaveBeenCalledWith('Missing binary data mode'); expect(response.end).toHaveBeenCalledWith('Malformed binary data ID');
}); });
it('should return 400 if binary data mode is invalid', async () => { it('should return 400 if binary data mode is invalid', async () => {

View File

@@ -47,14 +47,23 @@ export class BinaryDataController {
throw new BadRequestError('Missing binary data ID'); throw new BadRequestError('Missing binary data ID');
} }
if (!binaryDataId.includes(':')) { const separatorIndex = binaryDataId.indexOf(':');
throw new BadRequestError('Missing binary data mode');
if (separatorIndex === -1) {
throw new BadRequestError('Malformed binary data ID');
} }
const [mode] = binaryDataId.split(':'); const mode = binaryDataId.substring(0, separatorIndex);
if (!isValidNonDefaultMode(mode)) { if (!isValidNonDefaultMode(mode)) {
throw new BadRequestError('Invalid binary data mode'); throw new BadRequestError('Invalid binary data mode');
} }
const path = binaryDataId.substring(separatorIndex + 1);
if (path === '' || path === '/' || path === '//') {
throw new BadRequestError('Malformed binary data ID');
}
} }
private async setContentHeaders( private async setContentHeaders(