From 18572e90a6a4f72d21faa3bac4a7b467bd4e6c83 Mon Sep 17 00:00:00 2001 From: Acts1631 <69813585+acts-1631@users.noreply.github.com> Date: Sat, 1 Aug 2026 00:18:24 -0400 Subject: [PATCH] Limit ID3 compressed-frame expansion (#1382) A crafted compressed ID3v2 frame can declare an excessive output size and cause zlib to allocate memory based on attacker-controlled data. Bound decompression by an absolute 64 MiB limit and a 64:1 expansion ratio, while retaining normal ID3v2.3 length handling. --- taglib/mpeg/id3v2/id3v2frame.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index a496302f..dc3b6c3c 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "tdebug.h" #include "tstringlist.h" @@ -57,6 +58,9 @@ public: namespace { + constexpr unsigned int maxCompressedFrameOutputSize = 64U * 1024U * 1024U; + constexpr unsigned int maxCompressedFrameRatio = 64; + bool isValidFrameID(const ByteVector &frameID) { if(frameID.size() != 4) @@ -310,8 +314,16 @@ ByteVector Frame::fieldData(const ByteVector &frameData) const return ByteVector(); } - const ByteVector outData = zlib::decompress(frameData.mid(frameDataOffset), - frameDataLength); + const ByteVector compressedData = frameData.mid(frameDataOffset); + const uint64_t maxOutputSizeForInput = + static_cast(compressedData.size()) * maxCompressedFrameRatio; + if(frameDataLength > maxCompressedFrameOutputSize || + frameDataLength > maxOutputSizeForInput) { + debug("Compressed frame exceeds decompression limit"); + return ByteVector(); + } + + const ByteVector outData = zlib::decompress(compressedData, frameDataLength); if(!outData.isEmpty() && frameDataLength != outData.size()) { debug("frameDataLength does not match the data length returned by zlib"); }