From 3aa04e3be44b243e17663f77d63d7018df5d8f29 Mon Sep 17 00:00:00 2001 From: Acts1631 <69813585+acts-1631@users.noreply.github.com> Date: Sat, 1 Aug 2026 00:12:47 -0400 Subject: [PATCH] Fix Shorten AIFF chunk offset wrap (#1381) A crafted embedded AIFF chunk size could wrap the parser offset and make it repeatedly process the same chunk, causing a denial of service. Validate AIFF chunk headers and padded sizes against the remaining verbatim-header data, and advance every parsed chunk to its checked end. --- taglib/shorten/shortenfile.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/taglib/shorten/shortenfile.cpp b/taglib/shorten/shortenfile.cpp index a77d5cb8..480b50d5 100644 --- a/taglib/shorten/shortenfile.cpp +++ b/taglib/shorten/shortenfile.cpp @@ -471,14 +471,27 @@ void Shorten::File::read(AudioProperties::ReadStyle propertiesStyle) auto sawCommonChunk = false; while(offset < chunkData.size()) { + if(chunkData.size() - offset < 8) { + debug("Shorten::File::read() -- Truncated AIFF chunk header."); + setValid(false); + return; + } + chunkID = chunkData.toUInt(offset, true); offset += 4; - auto chunkSize = chunkData.toUInt(offset, true); + const auto chunkSize = chunkData.toUInt(offset, true); offset += 4; // All chunks must have an even length but the pad byte is not included in chunkSize - chunkSize += (chunkSize & 1); + const uint64_t paddedChunkSize = static_cast(chunkSize) + (chunkSize & 1); + if(paddedChunkSize > chunkData.size() - offset) { + debug("Shorten::File::read() -- AIFF chunk exceeds verbatim header."); + setValid(false); + return; + } + + const unsigned int chunkEnd = offset + static_cast(paddedChunkSize); switch(chunkID) { case 0x434f4d4d /*'COMM'*/: @@ -523,11 +536,11 @@ void Shorten::File::read(AudioProperties::ReadStyle propertiesStyle) break; } - // Skip all other chunks default: - offset += chunkSize; break; } + + offset = chunkEnd; } if(!sawCommonChunk) {