From 40838a8bebe986851aa5192ce3570653976e49cf Mon Sep 17 00:00:00 2001 From: David Mihalcik Date: Wed, 18 Sep 2024 12:56:49 -0400 Subject: [PATCH] fix(lib): Adds a 10 MiB cap to manifest size This should help prevent an avenue for DoSes --- lib/tdf3/src/utils/zip-reader.ts | 7 +++++++ lib/tests/mocha/unit/zip.spec.ts | 31 ++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) 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'); + } + }); +});