diff --git a/lib/tdf3/src/utils/zip-reader.ts b/lib/tdf3/src/utils/zip-reader.ts index 585129ee..e76dff48 100644 --- a/lib/tdf3/src/utils/zip-reader.ts +++ b/lib/tdf3/src/utils/zip-reader.ts @@ -8,6 +8,8 @@ const CD_SIGNATURE = 0x02014b50; const CENTRAL_DIRECTORY_RECORD_FIXED_SIZE = 46; const LOCAL_FILE_HEADER_FIXED_SIZE = 30; const VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45; +const manifestMaxSize = 1024 * 1024 * 10; // 10 MB + const cp437 = '\u0000☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ '; @@ -92,6 +94,11 @@ export class ZipReader { throw new Error('Unable to retrieve CD manifest'); } const byteStart = cdObj.relativeOffsetOfLocalHeader + cdObj.headerLength; + if (cdObj.uncompressedSize > manifestMaxSize) { + throw new Error( + `manifest file too large: ${(cdObj.uncompressedSize >> 10).toLocaleString()} KiB` + ); + } const byteEnd = byteStart + cdObj.uncompressedSize; const manifest = await this.getChunk(byteStart, byteEnd); diff --git a/lib/tests/mocha/unit/zip.spec.ts b/lib/tests/mocha/unit/zip.spec.ts index 4b384795..a5386a27 100644 --- a/lib/tests/mocha/unit/zip.spec.ts +++ b/lib/tests/mocha/unit/zip.spec.ts @@ -1,7 +1,12 @@ import { expect } from 'chai'; import { encodeArrayBuffer } from '../../../src/encodings/base64.js'; -import { parseCDBuffer, readUInt64LE } from '../../../tdf3/src/utils/zip-reader.js'; +import { + CentralDirectory, + parseCDBuffer, + readUInt64LE, + ZipReader, +} from '../../../tdf3/src/utils/zip-reader.js'; import { ZipWriter, dateToDosDateTime, writeUInt64LE } from '../../../tdf3/src/utils/zip-writer.js'; describe('zip utilities', () => { @@ -170,3 +175,27 @@ describe('zip utilities', () => { }); }); }); + +describe('reader', () => { + it('fails on bad manifest size', async () => { + const reader = new ZipReader(async () => new Uint8Array([])); + const fileName = '0.manifest.json'; + try { + expect( + await reader.getManifest( + [ + { + fileName, + relativeOffsetOfLocalHeader: 0, + headerLength: 1024, + uncompressedSize: 1024 * 1024 * 128, + } as CentralDirectory, + ], + fileName + ) + ).to.be.undefined; + } catch (e) { + expect(e.message).to.contain('too large'); + } + }); +});