Talos Vulnerability Report

TALOS-2026-2367

MediaArea MediaInfoLib LXF parsing heap-based buffer overflow vulnerability

May 25, 2026
CVE Number

CVE-2026-25104

Summary

A heap-based buffer overflow vulnerability exists in the LXF 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-191 - Integer Underflow (Wrap or Wraparound)

Details

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

The .LXF format, also known as a LEITCH video format, is a proprietary video file format that can include audio and video streams.

During the parsing of an .LXF file, MediaInfoLib attempts to merge two audio channels into one, executing the following code:

    size_t Minimum=(size_t)-1;
    for (size_t Pos=0; Pos<Common->Channels.size(); Pos++)
        if (Minimum>Common->Channels[Pos]->Buffer_Size-Common->Channels[Pos]->Buffer_Offset)
            Minimum=Common->Channels[Pos]->Buffer_Size-Common->Channels[Pos]->Buffer_Offset;                                        (1)

    ...
    while (Minimum*8>=BitDepth)
    {
        switch (BitDepth)
        {
            ...
            case 20:
                ...
                for (size_t Pos=0; Pos+1<Common->Channels.size(); Pos+=2) {
                    ...
                    int8u* Channel1=Common->Channels[Pos]->Buffer+Common->Channels[Pos]->Buffer_Offset;                             (2.a)
                    int8u* Channel2=Common->Channels[Pos]->Buffer+Common->Channels[Pos]->Buffer_Offset;                             (2.b)

                    // Copy bytes from both channels to the merged channel                                                          (3)
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= Channel1[0];
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= Channel1[0];
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= Channel1[1];
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= (Channel2[0] <<   4) | (Channel1[2] & 0x0F);
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= (Channel2[1] <<   4) | (Channel2[0] >> 4  );  
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= (Channel2[2] <<   4) | (Channel2[1] >> 4  );  
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= (Channel1[3] <<   4) | (Channel1[2] >> 4  );  
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= (Channel1[4] <<   4) | (Channel1[3] >> 4  );  
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= (Channel2[2] & 0xF0) | (Channel1[4] >> 4  );  
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= Channel2[3];
                    Common->MergedChannel.Buffer[Common->MergedChannel.Buffer_Size++]= Channel2[4];
                    ...

                    Common->Channels[Pos]->Buffer_Offset+=5;
                    Common->Channels[Pos+1]->Buffer_Offset+=5;
                }
                Minimum-=5; //2.5 twice                                                                                             (4)
                break;

Minimum here denotes the minimum amount of audio bytes that should be merged. At (1) the code reads the variable Minimum directly from user input, since Common->Channels[Pos]->Buffer_Size is user-controlled and Buffer+Common->Channels[Pos]->Buffer_Offset is initialized to 0. The actual buffer is initialized with a size of 32768 bytes.

    channel()
    {
        Buffer=new int8u[32768];
        Buffer_Offset=0;
        Buffer_Size=0;
        Buffer_Size_Max=32768;
    }

For the case of BitDepth = 20 (again, user-controlled), the code attempts to merge the two audio channels executing the code at (2), (3) and (4).

Note that at (2), the code is supposed to get the different buffers for audio channels 1 and 2,however there appears to be a copy-paste bug that in essence has Channel2 point to exactly the same buffer as Channel1.

Then during execution of (3), the code copies data from the audio channels to a singular audio buffer (MergedChannel). Specifically, the code copies 5 bytes from each channel, for a total of 10 bytes in each iteration, with some byte-shuffling to merge the two interleaved audiochannels into one.

Finally, at (4), Minimum is decremented by 5 and then the next iteration continues. If Minimum = 8 then at the next iteration, it will be decremented to 3. During the follwing iteration, the value of 3 will be decremented by 5 to -2, or equivalently in two’s complement 0xfffffffffffffffe. As a result, the while loop will be executed for an indefinite amount of times, with the operations at (3) doing effectively a heap buffer overflow.

Normally, this would result in the code writing to memory ad infinitum until it tried to write to an unmapped memory address where the library would crash. However, it is easy to see that BitDepth resides in memory as well.

    (rr) p/x Common->MergedChannel.Buffer
    $9 = 0x5555563f6360
    (rr) p &BitDepth
    $10 = (ZenLib::int8u *) 0x5555564298d3 "\024\200\273"

It is evident here that Common->MergedChannel.Buffer lies before BitDepth in memory. Since the code will continue to overwrite the heap, at some point the BitDepth value will be overwritten. If the new value is not 16, 20 or 24 the code will continue to the default case which leads to an early return of the function.

        case BitDepth:
            case 16:
                ...
            case 20:
                ...
            case 24:
                ...
            default: ;
                // Not supported
                Reject();
                return;

As a result, if the code overwrites at least 0x33573 = 210291 bytes beyond the start of the buffer, the BitDepth value will be overwritten, the library won’t crash and execution will continue. Then, any subsequent attempts to use pointers that have been overwritten can lead to a remote code execution.

Crash Information

ASAN Report

==2125==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x52d000134400 at pc 0x5555575e13d2 bp 0x7fffffffd260 sp 0x7fffffffd258
WRITE of size 1 at 0x52d000134400 thread T0                                           
    #0 0x5555575e13d1 in MediaInfoLib::File_ChannelGrouping::Read_Buffer_Continue() /fuzz/src/Source/MediaInfo/Audio/File_ChannelGrouping.cpp:282:94
    #1 0x55555730a435 in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1489:5
    #2 0x5555573053a0 in MediaInfoLib::File__Analyze::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101:16
    #3 0x555557311c2b in MediaInfoLib::File__Analyze::Open_Buffer_Continue(MediaInfoLib::File__Analyze*, unsigned char const*, unsigned long, bool, double) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1455:10
    #4 0x55555665a3f9 in MediaInfoLib::File_Lxf::Audio_Stream(unsigned long) /fuzz/src/Source/MediaInfo/Multiple/File_Lxf.cpp:1549:9
    #5 0x555556655892 in MediaInfoLib::File_Lxf::Data_Parse() /fuzz/src/Source/MediaInfo/Multiple/File_Lxf.cpp:866:25
    #6 0x55555731c0ba in MediaInfoLib::File__Analyze::Data_Manage() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:2838:9
    #7 0x555557314052 in MediaInfoLib::File__Analyze::Buffer_Parse() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1948:10
    #8 0x55555730a80e in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1514:14
    #9 0x5555573053a0 in MediaInfoLib::File__Analyze::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101:16
    #10 0x555557555549 in MediaInfoLib::File__MultipleParsing::Read_Buffer_Continue() /fuzz/src/Source/MediaInfo/File__MultipleParsing.cpp:925:22
    #11 0x55555730a435 in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1489:5
    #12 0x5555573053a0 in MediaInfoLib::File__Analyze::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101:16
    #13 0x555555a500cf in MediaInfoLib::MediaInfo_Internal::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1723:11
    #14 0x555555a5357d in MediaInfoLib::MediaInfo_Internal::Open(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned long long) /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1511:5
    #15 0x555555932919 in LLVMFuzzerTestOneInput /fuzz/harness/harness.cpp:10:15
    #16 0x5555559327e9 in ExecuteFilesOnyByOne /AFLplusplus/utils/aflpp_driver/aflpp_driver.c:267:7
    #17 0x5555559325d9 in LLVMFuzzerRunDriver /AFLplusplus/utils/aflpp_driver/aflpp_driver.c
    #18 0x55555593217b in main /AFLplusplus/utils/aflpp_driver/aflpp_driver.c:323:10
    #19 0x7ffff7a091c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #20 0x7ffff7a0928a in __libc_start_main csu/../csu/libc-start.c:360:3
    #21 0x55555584e744 in _start (/fuzz/harness/build/harness_v26.01_afl_asan+0x2fa744) (BuildId: a55bfd24f258aa0f01360b5e260d883bae236a71)

0x52d000134400 is located 0 bytes after 32768-byte region [0x52d00012c400,0x52d000134400)
allocated by thread T0 here:                                                          
    #0 0x55555592fd11 in operator new[](unsigned long) (/fuzz/harness/build/harness_v25.10_afl_asan+0x3dbd11) (BuildId: a55bfd24f258aa0f01360b5e260d883bae236a71)
    #1 0x5555575da50f in MediaInfoLib::File_ChannelGrouping::common::channel::channel() /fuzz/src/Project/CMake/../../Source/MediaInfo/Audio/File_ChannelGrouping.h:54:24
    #2 0x5555575da50f in MediaInfoLib::File_ChannelGrouping::common::common() /fuzz/src/Project/CMake/../../Source/MediaInfo/Audio/File_ChannelGrouping.h:94:9
    #3 0x5555575da50f in MediaInfoLib::File_ChannelGrouping::Read_Buffer_Init() /fuzz/src/Source/MediaInfo/Audio/File_ChannelGrouping.cpp:129:20
    #4 0x5555572ff40b in MediaInfoLib::File__Analyze::Open_Buffer_Init(unsigned long long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:768:5
    #5 0x555556659a33 in MediaInfoLib::File_Lxf::Audio_Stream(unsigned long) /fuzz/src/Source/MediaInfo/Multiple/File_Lxf.cpp:1456:13
    #6 0x555556655892 in MediaInfoLib::File_Lxf::Data_Parse() /fuzz/src/Source/MediaInfo/Multiple/File_Lxf.cpp:866:25
    #7 0x55555731c0ba in MediaInfoLib::File__Analyze::Data_Manage() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:2838:9
    #8 0x555557314052 in MediaInfoLib::File__Analyze::Buffer_Parse() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1948:10
    #9 0x55555730a80e in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1514:14
    #10 0x5555573053a0 in MediaInfoLib::File__Analyze::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101:16
    #11 0x555557555549 in MediaInfoLib::File__MultipleParsing::Read_Buffer_Continue() /fuzz/src/Source/MediaInfo/File__MultipleParsing.cpp:925:22
    #12 0x55555730a435 in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop() /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1489:5
    #13 0x5555573053a0 in MediaInfoLib::File__Analyze::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101:16
    #14 0x555555a500cf in MediaInfoLib::MediaInfo_Internal::Open_Buffer_Continue(unsigned char const*, unsigned long) /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1723:11
    #15 0x555555a5357d in MediaInfoLib::MediaInfo_Internal::Open(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned long long) /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1511:5
    #16 0x555555932919 in LLVMFuzzerTestOneInput /fuzz/harness/harness.cpp:10:15
    #17 0x5555559327e9 in ExecuteFilesOnyByOne /AFLplusplus/utils/aflpp_driver/aflpp_driver.c:267:7

GDB Crash

    Here we see a controlled pointer (0x4444444444444444) taken from our PoC:
    
    Program received signal SIGSEGV, Segmentation fault.
    0x0000555555c5a23c in std::vector<std::vector<ZenLib::ZtringList, std::allocator<ZenLib::ZtringList> >, std::allocator<std::vector<ZenLib::ZtringList, std::allocator<ZenLib::ZtringList> > > >::operator[] (__n=<optimized out>, this=0x4444444444444444) at /usr/include/c++/13/bits/stl_vector.h:1129
    1129            return *(this->_M_impl._M_start + __n);

    (gdb) bt
    #0  0x0000555555c5a23c in std::vector<std::vector<ZenLib::ZtringList, std::allocator<ZenLib::ZtringList> >, std::allocator<std::vector<ZenLib::ZtringList, std::allocator<ZenLib::ZtringList> > > >::operator[] (__n=<optimized out>, this=0x4444444444444444) at /usr/include/c++/13/bits/stl_vector.h:1129
    #1  MediaInfoLib::File__Base::Clear (this=this@entry=0x555556429190) at /fuzz/src/Source/MediaInfo/File__Base.cpp:211
    #2  0x0000555555be96b6 in MediaInfoLib::File__Analyze::Clear (this=0x555556429190) at /fuzz/src/Project/CMake/../../Source/MediaInfo/File__Analyze.h:1221
    #3  MediaInfoLib::File__Analyze::Reject (this=0x555556429190, ParserName=0x0) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:3713
    #4  0x0000555555bf627d in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop (this=this@entry=0x555556429190) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1489
    #5  0x0000555555bf6b38 in MediaInfoLib::File__Analyze::Open_Buffer_Continue (this=0x555556429190, ToAdd=0x7ffff78ee0e5 'D' <repeats 14 times>, "yyyyy", ToAdd_Size=8) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101
    #6  0x0000555555bf7df8 in MediaInfoLib::File__Analyze::Open_Buffer_Continue (this=this@entry=0x5555561fd550, Sub=0x555556429190, ToAdd=0x7ffff78ee0e5 'D' <repeats 14 times>, "yyyyy", ToAdd_Size=8, IsNewPacket=IsNewPacket@entry=true, Ratio=Ratio@entry=1) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1455
    #7  0x00005555558fd068 in MediaInfoLib::File_Lxf::Audio_Stream (this=0x5555561fd550, Pos=3) at /fuzz/src/Source/MediaInfo/Multiple/File_Lxf.cpp:1549
    #8  0x00005555558fd8a1 in MediaInfoLib::File_Lxf::Data_Parse (this=0x5555561fd550) at /fuzz/src/Source/MediaInfo/Multiple/File_Lxf.cpp:866
    #9  0x0000555555bf3bb2 in MediaInfoLib::File__Analyze::Data_Manage (this=this@entry=0x5555561fd550) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:2838
    #10 0x0000555555bf5fc0 in MediaInfoLib::File__Analyze::Buffer_Parse (this=this@entry=0x5555561fd550) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1948
    #11 0x0000555555bf6128 in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop (this=this@entry=0x5555561fd550) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1514
    #12 0x0000555555bf6b38 in MediaInfoLib::File__Analyze::Open_Buffer_Continue (this=0x5555561fd550, ToAdd=0x7ffff78ee010 "LEITCH", ToAdd_Size=315) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101
    #13 0x0000555555c5aaf3 in MediaInfoLib::File__MultipleParsing::Read_Buffer_Continue (this=0x5555561bcba0) at /fuzz/src/Source/MediaInfo/File__MultipleParsing.cpp:925
    #14 0x0000555555bf627d in MediaInfoLib::File__Analyze::Open_Buffer_Continue_Loop (this=this@entry=0x5555561bcba0) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1489
    #15 0x0000555555bf6b38 in MediaInfoLib::File__Analyze::Open_Buffer_Continue (this=0x5555561bcba0, ToAdd=0x7ffff78ee010 "LEITCH", ToAdd_Size=315) at /fuzz/src/Source/MediaInfo/File__Analyze.cpp:1101
    #16 0x0000555555665bab in MediaInfoLib::MediaInfo_Internal::Open_Buffer_Continue (this=this@entry=0x5555561698b0, ToAdd=ToAdd@entry=0x7ffff78ee010 "LEITCH", ToAdd_Size=ToAdd_Size@entry=315) at /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1723
    #17 0x0000555555666490 in MediaInfoLib::MediaInfo_Internal::Open (this=0x5555561698b0, Begin=0x7ffff78ee010 "LEITCH", Begin_Size=315, End=0x0, End_Size=0, File_Size=315) at /fuzz/src/Source/MediaInfo/MediaInfo_Internal.cpp:1511
    #18 0x0000555555635a1e in LLVMFuzzerTestOneInput (data=0x7ffff78ee010 "LEITCH", size=315) at harness.cpp:10
    #19 0x000055555563597a in ExecuteFilesOnyByOne (argc=2, argv=0x7fffffffe398, callback=callback@entry=0x5555556359c0 <LLVMFuzzerTestOneInput(uint8_t const*, size_t)>) at aflpp_driver.c:267
    #20 0x000055555563576a in LLVMFuzzerRunDriver (argcp=argcp@entry=0x7fffffffe25c, argvp=argvp@entry=0x7fffffffe260, callback=0x5555556359c0 <LLVMFuzzerTestOneInput(uint8_t const*, size_t)>) at aflpp_driver.c:381
    #21 0x000055555563530c in main (argc=2, argv=0x7fffffffe398) at aflpp_driver.c:323

Timeline

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

Credit

Dimitrios Tatsis of Cisco TALOS