Talos Vulnerability Report

TALOS-2026-2371

MediaArea MediaInfoLib LXF element parsing heap-based buffer overflow vulnerability

May 20, 2026
CVE Number

CVE-2026-28764

Summary

A heap-based buffer overflow vulnerability exists in the LXF element parsing functionality of MediaInfoLib (version(s): 26.01). A specially crafted .lxf file can lead to arbitrary code execution. An attacker can provide a malicious file to trigger this vulnerability.

Confirmed Vulnerable Versions

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

MediaInfoLib (version(s): 26.01)

Product URLs

MediaInfoLib - https://github.com/MediaArea/MediaInfoLib

CVSSv3 Score

7.8 - CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-823 - Use of Out-of-range Pointer Offset

Details

MediaInfo(Lib) is a convenient unified display of technical information and metadata for video and audio files.

The MediaInfo library, during parsing of an input file, initializes a File__Analyze object that contains various methods and variables used for analyzing the input data. This class defines an Element vector with 64 objects, one for each individual element of a media file.

class File__Analyze : public File__Base
{
    ...
    std::vector<element_details> Element;

    File__Analyze ()
    {
        ...
        Element.resize(64);                                         (1)
        ...
    }
}

In File__Analyze::Open_Buffer_Continue_Loop(), the library proceeds to parse the input data in a while loop at (2) below.

bool File__Analyze::Open_Buffer_Continue_Loop ()
{
    ...
    while (Buffer_Offset<Buffer_Size)                               (2)
        if (!Buffer_Parse())
            break;
    ...
}

In each iteration, Buffer_Parse() eventually calls Header_Manage().

bool File__Analyze::Header_Manage()
{
    ...
    Element_Begin0();                                               (3)

    Header_Size = Element_Offset;                                   (4)
    Buffer_Offset += (size_t)Header_Size;                           (5)
    Element_Offset = 0;
    ...
}

After parsing a portion of the input data, at (4) and (5) the Buffer_Offset variable is incremented by Element_Offset so parsing can continue to the rest of the data.

During parsing of an LXF file, the MediaInfo library reads the header size and keeps track of the currently processed input.

void File_Lxf::Header_Parse()
{
    ...
    Get_L4 (HeaderSize, "Header size");                     (6)
    ...
    if (Element_Offset < HeaderSize)                        (7)
        Skip_XX(Header_Size-Element_Offset, "Unknown");     (8)
    ...
}

void File__Analyze::Skip_XX(int64u Bytes, const char* Name)
{
    ...
    Element_Offset+=Bytes;                                  (9)
}

At (6) the code reads the HeaderSize from the input header. At (7) and (8), if Element_Offset is less than HeaderSize, the code proceeds to skip a number of bytes of the input equal to their difference at (8). Note however that at (7), HeaderSize (without an underscore) is used for the comparison but at (8), Header_Size (with an underscore) is used for the subtraction, in what appears to be a typographic error. Header_Size is initialized to 0 during initialization of the File__Analyze object.

File__Analyze::File__Analyze ()
:File__Base()
{
    ...
    Header_Size=0;
    ...
}

As a result, the operation at (9) becomes the following:

Element_Offset += Bytes 
Element_Offset = Element_Offset + Bytes
Element_Offset = Element_Offset + (Header_Size - Element_Offset)
Element_Offset = Element_Offset + (0 - Element_Offset)
Element_Offset = Element_Offset - Element_Offset
Element_Offset = Element_Offset - Element_Offset
Element_Offset = 0

Effectively, Element_Offset is set to 0, if the condition at (7) is true, that is, if Element_Offset is less than HeaderSize.

During execution of the loop at (2), since Element_Offset is 0, Buffer_Offset at (5) will remain unchanged in each iteration. As a consequence, the loop at (2) becomes an infinite loop, since the Buffer_Offset never changes and the exit condition of the loop at (2) is never true.

In the Header_Manage() function which is called in every iteration of the loop, the Element_Begin() function is called at (3) (with the Element_Begin0 define) that keeps the state of parsed elements in the Element vector from (1):

#define Element_Begin0() Element_Begin()

void File__Analyze::Element_Begin()
{
    //Level
    Element_Level++;                                                                        (10)

    //Element
    Element[Element_Level].Code=0;                                                          (11.a)
    Element[Element_Level].Next=Element[Element_Level-1].Next;                              (11.b)
    Element[Element_Level].WaitForMoreData=Element[Element_Level-1].WaitForMoreData;        (11.c)
    Element[Element_Level].UnTrusted=Element[Element_Level-1].UnTrusted;                    (11.d)
    Element[Element_Level].IsComplete=Element[Element_Level-1].IsComplete;                  (11.e)

    #if MEDIAINFO_TRACE
    Element[Element_Level].TraceNode.Init();                                                (12)
    ...
    #endif //MEDIAINFO_TRACE
}

In each iteration, Element_Level will be incremented at (10). Note that there is no code to check that Element_Level is within the bounds of the Element vector which holds 64 objects. Consequently, when Element_Level becomes 64, the operations at (11) and (12) access memory beyond the last element of the Element vector, leading to a heap buffer overflow.

In this heap overflow scenario, the code assumes that the current Element[Element_Level] represents an element_details object. At the set of operations at (11), the code will overwrite data on the heap, copying data from the previous object. At (12), we see a call to element_details::Element_Node::Init():

std::string                      Name;
Element_Node_Data                Value;
std::vector<Element_Node_Info*>  Infos;
std::vector<Element_Node*>       Children;

void element_details::Element_Node::Init()
{
    Pos = 0;
    Size = 0;
    Name.clear();                                       (13)
    Value.clear();                                      (14)
    if (Children.size() && OwnChildren)
        for (size_t i = 0; i < Children.size(); ++i)
            delete Children[i];                         (15)
    Children.clear();
    if (OwnChildren && Infos.size())
        for (size_t i = 0; i < Infos.size(); ++i)
            delete Infos[i];                            (16)
    ...
}

The current object will point to heap data directly after the allocation of the original Element vector. As a result, an attacker able to control the memory layout will be able to create a fake object in memory. In this scenario, the objects Name, Value, as well as the Children and Infos vectors will be controlled by an attacker, leading to exploitation of an arbitrary free scenario at locations (13)-(16) that can lead to code execution.

Crash Information

ASAN crash information:

==45863==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x525000036f00 at pc 0x5555566e92ed bp 0x7fffffffd750 sp 0x7fffffffd748
WRITE of size 8 at 0x525000036f00 thread T0                                              
    #0 0x5555566e92ec in MediaInfoLib::File__Analyze::Element_Begin(char const*) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:3139:32
    #1 0x5555566e2925 in MediaInfoLib::File__Analyze::Header_Manage() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:2678:5
    #2 0x5555566deb93 in MediaInfoLib::File__Analyze::Buffer_Parse() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1958:10
    #3 0x5555566d91a6 in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1528:14
    #4 0x5555566d69d4 in MediaInfoLib::File__Analyze::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1115:16
    #5 0x555556801839 in MediaInfoLib::File__MultipleParsing::Read_Buffer_Continue() /fuzz/src/Source/MediaInfo/File__MultipleParsing.cpp:931:22
    #6 0x5555566d8f6e in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1503:5
    #7 0x5555566d69d4 in MediaInfoLib::File__Analyze::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1115:16
    #8 0x5555559db903 in MediaInfoLib::MediaInfo_Internal::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1723:11
    #9 0x5555559dc7b9 in MediaInfoLib::MediaInfo_Internal::Open(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned long long) /fuzz/src/Source/Medi
aInfo/MediaInfo_Internal.cpp:1511:5         
    #10 0x555555948dd1 in LLVMFuzzerTestOneInput /fuzz/harness/harness.cpp:6:15
    #11 0x555555948cc9 in ExecuteFilesOnyByOne /AFLplusplus/utils/aflpp_driver/aflpp_driver.c:267:7
    #12 0x555555948ab9 in LLVMFuzzerRunDriver /AFLplusplus/utils/aflpp_driver/aflpp_driver.c
    #13 0x55555594865b in main /AFLplusplus/utils/aflpp_driver/aflpp_driver.c:323:10
    #14 0x7ffff7a091c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #15 0x7ffff7a0928a in __libc_start_main csu/../csu/libc-start.c:360:3
    #16 0x555555864c24 in _start (/fuzz/harness/build/harness_v26.01_vanilla_asan+0x310c24) (BuildId: 3fbcb2f1e982dfde280a167351fa91c95b983301)
                                            
0x525000036f00 is located 0 bytes after 9728-byte region [0x525000034900,0x525000036f00)
allocated by thread T0 here: 
    #0 0x5555559460d1 in operator new(unsigned long) (/fuzz/harness/build/harness_v26.01_vanilla_asan+0x3f20d1) (BuildId: 3fbcb2f1e982dfde280a167351fa91c95b983301)
    #1 0x555556700431 in std::__new_allocator<MediaInfoLib::element_details>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits
/new_allocator.h:151:27                     
    #2 0x555556700431 in std::allocator_traits<std::allocator<MediaInfoLib::element_details>>::allocate(std::allocator<MediaInfoLib::element_details>&, unsigned long) /usr/lib/gcc
/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20               
    #3 0x555556700431 in std::_Vector_base<MediaInfoLib::element_details, std::allocator<MediaInfoLib::element_details>>::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/
13/../../../../include/c++/13/bits/stl_vector.h:381:20                                   
    #4 0x555556700431 in std::vector<MediaInfoLib::element_details, std::allocator<MediaInfoLib::element_details>>::_M_default_append(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/
13/../../../../include/c++/13/bits/vector.tcc:663:34                                     
    #5 0x5555566d198c in std::vector<MediaInfoLib::element_details, std::allocator<MediaInfoLib::element_details>>::resize(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../..
/../include/c++/13/bits/stl_vector.h:1016:4 
    #6 0x5555566d198c in MediaInfoLib::File__Analyze::File__Analyze() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:675:13
    #7 0x555556019295 in MediaInfoLib::File_Lxf::File_Lxf() /fuzz/src/Source/MediaInfo/Multiple/File_Lxf.cpp:115:2
    #8 0x5555567f1da4 in MediaInfoLib::File__MultipleParsing::File__MultipleParsing() /fuzz/src/Source/MediaInfo/File__MultipleParsing.cpp:521:30
    #9 0x5555559daee2 in MediaInfoLib::MediaInfo_Internal::Open_Buffer_Init(unsigned long long, std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar
_t>> const&) /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1548:22                   
    #10 0x5555559dc786 in MediaInfoLib::MediaInfo_Internal::Open(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned long long) /fuzz/src/Source/Med
iaInfo/MediaInfo_Internal.cpp:1510:5        
    #11 0x555555948dd1 in LLVMFuzzerTestOneInput /fuzz/harness/harness.cpp:6:15
    #12 0x555555948cc9 in ExecuteFilesOnyByOne /AFLplusplus/utils/aflpp_driver/aflpp_driver.c:267:7

Timeline

2026-03-25 - Initial Vendor Contact
2026-03-25 - Vendor Disclosure
2026-05-12 - Vendor Patch Release
2026-05-21 - Public Release

Credit

Dimitrios Tatsis of Cisco TALOS