TALOS-2026-2412
CVE-2026-41216
A invalid pointer dereference vulnerability exists in the vtkPNGReader::ExecuteInformation functionality of vtk (version(s): 9.6). A specially crafted .png file can lead to a denial of service. An attacker can provide a malicious file to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
vtk (version(s): 9.6)
vtk - https://vtk.org/
7.5 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE-825 - Expired Pointer Dereference
VTK, or the Visualization Toolkit, is an open-source software system for 3D computer graphics, image processing, and scientific visualization. It provides a large collection of algorithms and data structures for rendering, volume visualization, geometric processing, and interaction.
The interesting part of the crash details is the following :
#3 0x00007f00855f1dae in vtkPNGReader::vtkInternals::HandleLibPngError (this=<optimized out>, pngPtr=<error reading variable: Cannot access memory at address 0x7c2008000000207c>,
infoPtr=<error reading variable: Cannot access memory at address 0x49484452>, fp=0x515000003000) at /opt/vtk-src/IO/Image/vtkPNGReader.cxx:265
So when looking into the call stack we can observe that vtkPNGReader::vtkInternals::HandleLibPngError is called from vtkPNGReader::ExecuteInformation
Following source extract of vtkPNGReader::ExecuteInformation calling HandleLibPngError LINE70 then continue flow of execution.
LINE1 void vtkPNGReader::ExecuteInformation()
LINE2 {
LINE3 vtkInternals* impl = this->Internals;
[...]
LINE58 png_structp png_ptr = nullptr;
LINE59 png_infop info_ptr = nullptr;
LINE60 png_infop end_info = nullptr;
LINE61 if (!impl->CreateLibPngStructs(png_ptr, info_ptr, end_info))
LINE62 {
LINE63 if (fp)
LINE64 {
LINE65 fclose(fp);
LINE66 }
LINE67 return;
LINE68 }
LINE69
LINE70 impl->HandleLibPngError(png_ptr, info_ptr, fp);
LINE71 impl->InitLibPngInput(this, png_ptr, &stream, fp);
LINE72
LINE73 png_read_info(png_ptr, info_ptr);
LINE74
[...]
LINE143 }
Looking into HandleLibPngError source code :
LINE146 void HandleLibPngError(png_structp pngPtr, png_infop infoPtr, FILE* fp)
LINE147 {
LINE148 if (setjmp(png_jmpbuf(pngPtr)))
LINE149 {
LINE150 png_destroy_read_struct(&pngPtr, &infoPtr, (png_infopp) nullptr);
LINE151 if (fp)
LINE152 {
LINE153 fclose(fp);
LINE154 }
LINE155 }
LINE156 }
We notice some setjmp instruction in order to call png_destroy_read_struct which will be use in case of error and cause the stack and some registers to be saved for later reuse. Then HandleLibPngError ends and flow continue execution coming back to vtkPNGReader::ExecuteInformation LINE71 to init and read png info through call to png_read_info LINE73. The issue is happening as vtkPNGReader::ExecuteInformation() crashes with SIGSEGV or SIGABRT when processing a malformed PNG file, as longjmp is triggered by png_read_info. This is happening because the longjmp returns into HandleLibPngError. At the time longjmp fires, HandleLibPngError() has already returned and its stack frame has been overwritten by subsequent calls (InitLibPngInput, png_read_info). The fp parameter slot in that dead frame now contains garbage from whatever the last callee placed there. The issue is the fclose(fp) LINE153 as fp is not pointing anymore to the file pointer. The correct approach should have been to implement the setjmp directly intovtkPNGReader::ExecuteInformation.
fclose() dereferences fp as a FILE structure:
1. Reads fp->_IO_file_jumps — the FILE vtable pointer
2. Calls a function pointer from that vtable (_IO_FINISH)
If the attacker controls the memory region fp points to (e.g., via the PNG file content loaded in heap), they can supply a crafted vtable and redirect execution.
glibc ≥ 2.24 includes _IO_vtable_check() which validates that the vtable is within the expected range. This converts some exploitation attempts into SIGABRT instead of arbitrary code execution. However, this mitigation is absent on glibc <= 2.24 and on other C libraries.
Program received signal SIGSEGV, Segmentation fault.
0x00007f006dc9402d in png_free_data () from /lib/x86_64-linux-gnu/libpng16.so.16
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────────────────────────────────────────────────────────[ LAST SIGNAL ]─────────────────────────────────────────────────────────────────────────────────────────────────
current pc: 0x7f006dc9402d
─────────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]──────────────────────────────────────────────────────────────────────────────
RAX 0
*RBX 0x49484452
*RCX 0xffffffff ◂— 0
*RDX 0xffff
*RDI 0x7c2008000000207c
*RSI 0x49484452
*R8 0x7ffee970c920 —▸ 0x513000000740 ◂— 0
*R9 0x7ffee970c9d0 —▸ 0x7ffee970cae0 —▸ 0x7ffee970cb10 —▸ 0x7ffee970cbd0 —▸ 0x7ffee970cc90 ◂— ...
*R10 0x7fffffffff01
*R11 0x201
*R12 0x49484452
*R13 0xffff
*R14 0xfffdd2e1924 ◂— 0
*R15 0x7f005bfe7800 ◂— 0xbebebebebebebebe
*RBP 0x7ffee970c8c0 —▸ 0x7ffee970c8e0 —▸ 0x7ffee970c910 —▸ 0x7ffee970c9d0 —▸ 0x7ffee970cae0 ◂— ...
*RSP 0x7ffee970c880 ◂— 0
*RIP 0x7f006dc9402d (png_free_data+45) ◂— mov rsi, qword ptr [rsi + 0xa0]
──────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────────────────────────────────────────────────────────
► 0x7f006dc9402d <png_free_data+45> mov rsi, qword ptr [rsi + 0xa0] <Cannot dereference [0x494844f2]>
0x7f006dc94034 <png_free_data+52> mov r12, rdi R12 => 0x7c2008000000207c
0x7f006dc94037 <png_free_data+55> mov r14d, ecx R14D => 0xffffffff ◂— 0
0x7f006dc9403a <png_free_data+58> mov edx, dword ptr [rbx + 0x12c] <Cannot dereference [0x4948457e]>
0x7f006dc94040 <png_free_data+64> mov eax, r13d EAX => 0xffff
0x7f006dc94043 <png_free_data+67> and eax, edx
0x7f006dc94045 <png_free_data+69> test rsi, rsi
0x7f006dc94048 <png_free_data+72> je png_free_data+198 <png_free_data+198>
0x7f006dc9404a <png_free_data+74> test ah, 0x40
0x7f006dc9404d <png_free_data+77> je png_free_data+198 <png_free_data+198>
0x7f006dc9404f <png_free_data+79> cmp ecx, -1
────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7ffee970c880 ◂— 0
... ↓ 2 skipped
03:0018│-028 0x7ffee970c898 ◂— 0x7c2008000000207c /* '| ' */
04:0020│-020 0x7ffee970c8a0 ◂— 0x49484452 /* 'RDHI' */
05:0028│-018 0x7ffee970c8a8 —▸ 0x7ffee970c960 ◂— 0
06:0030│-010 0x7ffee970c8b0 —▸ 0xfffdd2e1924 ◂— 0
07:0038│-008 0x7ffee970c8b8 —▸ 0x7f005bfe7800 ◂— 0xbebebebebebebebe
──────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────────────────────
► 0 0x7f006dc9402d png_free_data+45
1 0x7f006dc94629 png_destroy_info_struct+57
2 0x7f006dc97412 png_destroy_read_struct+66
3 0x7f00855f1dae vtkPNGReader::vtkInternals::HandleLibPngError(png_struct_def*, png_info_def*, _IO_FILE*)+206
4 0x7f00855ec742 vtkPNGReader::ExecuteInformation()+4482
5 0x7f0085405fa2 vtkImageReader2::RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*)+162
6 0x7f0083f7ced8 vtkExecutive::CallAlgorithm(vtkInformation*, int, vtkInformationVector**, vtkInformationVector*)+504
7 0x7f00840c2870 vtkStreamingDemandDrivenPipeline::ExecuteInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*)+224
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> k
#0 0x00007f006dc9402d in png_free_data () from /lib/x86_64-linux-gnu/libpng16.so.16
#1 0x00007f006dc94629 in png_destroy_info_struct () from /lib/x86_64-linux-gnu/libpng16.so.16
#2 0x00007f006dc97412 in png_destroy_read_struct () from /lib/x86_64-linux-gnu/libpng16.so.16
#3 0x00007f00855f1dae in vtkPNGReader::vtkInternals::HandleLibPngError (this=<optimized out>, pngPtr=<error reading variable: Cannot access memory at address 0x7c2008000000207c>,
infoPtr=<error reading variable: Cannot access memory at address 0x49484452>, fp=0x515000003000) at /opt/vtk-src/IO/Image/vtkPNGReader.cxx:265
#4 0x00007f00855ec742 in vtkPNGReader::ExecuteInformation (this=0x521000001500) at /opt/vtk-src/IO/Image/vtkPNGReader.cxx:360
#5 0x00007f0085405fa2 in vtkImageReader2::RequestInformation (this=0x516000000080, outputVector=0x50e000000820) at /opt/vtk-src/IO/Image/vtkImageReader2.cxx:394
#6 0x00007f0083f7ced8 in vtkExecutive::CallAlgorithm (this=0x512000000640, request=<optimized out>, direction=<optimized out>, inInfo=<optimized out>, outInfo=<optimized out>)
at /opt/vtk-src/Common/ExecutionModel/vtkExecutive.cxx:723
#7 0x00007f00840c2870 in vtkStreamingDemandDrivenPipeline::ExecuteInformation (this=0x512000000640, request=<optimized out>, inInfoVec=<optimized out>, outInfoVec=0x50e000000820)
at /opt/vtk-src/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx:465
#8 0x00007f0083f4be49 in vtkDemandDrivenPipeline::ProcessRequest (this=0x512000000640, request=0x50e0000011c0, inInfoVec=<optimized out>, outInfoVec=<optimized out>)
at /opt/vtk-src/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:209
#9 0x00007f00840bdd33 in vtkStreamingDemandDrivenPipeline::ProcessRequest (this=0x512000000640, request=0x50e0000011c0, inInfoVec=<optimized out>, outInfoVec=<optimized out>)
at /opt/vtk-src/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx:372
#10 0x00007f0083f0b610 in vtkAlgorithm::UpdateInformation (this=<optimized out>) at /opt/vtk-src/Common/ExecutionModel/vtkAlgorithm.cxx:1752
#11 0x000055c25989ef70 in ExercisePNGReaderAPIs (reader=0x516000000080, input="/manuwork/advisories/tests_202f92dbec9f1eaa6f45b34d3bd6f0035b4ac1a3.png") at /manuwork/medical_harness_vtk/harness_png.cpp:49
#12 main (argc=0x5, argv=<optimized out>) at /manuwork/medical_harness_vtk/harness_png.cpp:98
#13 0x00007f00758b91ca in __libc_start_call_main (main=main@entry=0x55c25989d1c8 <main(int, char**)>, argc=argc@entry=0x5, argv=argv@entry=0x7ffee970d178) at ../sysdeps/nptl/libc_start_call_main.h:58
#14 0x00007f00758b928b in __libc_start_main_impl (main=0x55c25989d1c8 <main(int, char**)>, argc=0x5, argv=0x7ffee970d178, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7ffee970d168) at ../csu/libc-start.c:360
#15 0x000055c2597b9895 in _start ()
Vendor Link: https://vtk.org/download/
2026-06-23 - Vendor Notification
2026-06-25 - Vendor Acknowledged
2026-06-30 - 7-Day
2026-07-02 - Follow-Up Sent
2026-07-07 - Vendor Replied, Dev Team Working
2026-08-07 - 45-Day
2026-08-22 - 60-Day
2026-09-15 - Follow-Up Sent
2026-09-21 - 90-Day
2026-09-23 - Vendor Replied, Dev Team Working
2026-10-12 - Advised Vendor Cisco Will Publish And Close Out
Emmanuel Tacheau of Cisco Talos