Skip to content

Commit e775ba5

Browse files
fix(lib): Adds a 10 MiB cap to manifest size (#353)
This should help prevent an avenue for DoSes
1 parent 48b2442 commit e775ba5

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

lib/tdf3/src/utils/zip-reader.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const CD_SIGNATURE = 0x02014b50;
88
const CENTRAL_DIRECTORY_RECORD_FIXED_SIZE = 46;
99
const LOCAL_FILE_HEADER_FIXED_SIZE = 30;
1010
const VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45;
11+
const manifestMaxSize = 1024 * 1024 * 10; // 10 MB
12+
1113
const cp437 =
1214
'\u0000☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ';
1315

@@ -92,6 +94,11 @@ export class ZipReader {
9294
throw new Error('Unable to retrieve CD manifest');
9395
}
9496
const byteStart = cdObj.relativeOffsetOfLocalHeader + cdObj.headerLength;
97+
if (cdObj.uncompressedSize > manifestMaxSize) {
98+
throw new Error(
99+
`manifest file too large: ${(cdObj.uncompressedSize >> 10).toLocaleString()} KiB`
100+
);
101+
}
95102
const byteEnd = byteStart + cdObj.uncompressedSize;
96103
const manifest = await this.getChunk(byteStart, byteEnd);
97104

lib/tests/mocha/unit/zip.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { expect } from 'chai';
22

33
import { encodeArrayBuffer } from '../../../src/encodings/base64.js';
4-
import { parseCDBuffer, readUInt64LE } from '../../../tdf3/src/utils/zip-reader.js';
4+
import {
5+
CentralDirectory,
6+
parseCDBuffer,
7+
readUInt64LE,
8+
ZipReader,
9+
} from '../../../tdf3/src/utils/zip-reader.js';
510
import { ZipWriter, dateToDosDateTime, writeUInt64LE } from '../../../tdf3/src/utils/zip-writer.js';
611

712
describe('zip utilities', () => {
@@ -170,3 +175,27 @@ describe('zip utilities', () => {
170175
});
171176
});
172177
});
178+
179+
describe('reader', () => {
180+
it('fails on bad manifest size', async () => {
181+
const reader = new ZipReader(async () => new Uint8Array([]));
182+
const fileName = '0.manifest.json';
183+
try {
184+
expect(
185+
await reader.getManifest(
186+
[
187+
{
188+
fileName,
189+
relativeOffsetOfLocalHeader: 0,
190+
headerLength: 1024,
191+
uncompressedSize: 1024 * 1024 * 128,
192+
} as CentralDirectory,
193+
],
194+
fileName
195+
)
196+
).to.be.undefined;
197+
} catch (e) {
198+
expect(e.message).to.contain('too large');
199+
}
200+
});
201+
});

0 commit comments

Comments
 (0)