pydub_wav_dos_pocs.zip
Describe the bug
`AudioSegment.from_wav()` and `AudioSegment.from_file()` parse WAV headers and trust `nSamplesPerSec` and `nChannels`
without bounds checking. Malformed WAV files with absurd values load successfully but cause CPU exhaustion or OOM when
downstream operations like `export()`, `len()`, or `frame_rate` calculations trigger `ffmpeg` processing.
This allows a 44-byte file to DoS any service that uses `pydub` to process user-uploaded WAVs.
1. Download `pydub_wav_dos_pocs.zip` attached to this issue
2. Extract and run:
```python
from pydub import AudioSegment
# PoC 1: Samplerate overflow - HANG/OOM on export
a = AudioSegment.from_wav('evil.wav') # loads: frame_rate=100000000
a.export('out.mp3', format='mp3') # hangs/allocates huge memory
# PoC 2: Channel overflow - ffmpeg error/OOM on export
b = AudioSegment.from_wav('evil_channels.wav') # loads: channels=65535
b.export('out.mp3', format='mp3') # ffmpeg: Invalid channel layout
- Observe: Files load without error, then exhaust resources during processing.
Expected behavior
pydub should reject WAV files with unreasonable header values before returning an AudioSegment. Similar to how ffmpeg itself rejects data_size=0xFFFFFFFF with "invalid start code", pydub should fail fast on sample_rate > 384000 or channels > 8.
Actual behavior
>>> a = AudioSegment.from_wav('evil.wav')
>>> a.frame_rate
100000000 # accepted
>>> a.channels
1
>>> len(a)
0 # duration calc underflows but doesn't error
Environment
- pydub: 0.25.1
- Python: 3.9.16
- ffmpeg: 5.1.4
- OS: Linux x86_64
Impact
Any service accepting user WAV uploads via pydub is vulnerable to DoS. A 44-byte file can cause:
- CPU exhaustion:
ffmpeg attempts to resample 100MHz audio
- Memory exhaustion:
ffmpeg attempts 64k-channel processing
- Request thread hangs until killed by timeout
Additional test cases in zip:
evil_bits.wav: bits_per_sample=65535 — loads, fails faster on export
evil_data_size.wav: data_size=0xFFFFFFFF — already rejected by ffmpeg, included to show where validation exists
Suggested fix
Add bounds checks after parsing fmt chunk in audio_segment.py:
MAX_SAMPLE_RATE = 384000 # DXD/DSD rates
MIN_SAMPLE_RATE = 8000 # telephone quality
MAX_CHANNELS = 8 # 7.1 surround
if not MIN_SAMPLE_RATE <= self.frame_rate <= MAX_SAMPLE_RATE:
raise CouldntDecodeError(f"Sample rate {self.frame_rate} out of bounds")
if not 1 <= self.channels <= MAX_CHANNELS:
raise CouldntDecodeError(f"Channel count {self.channels} out of bounds")
if self.sample_width not in (1, 2, 3, 4): # 8,16,24,32-bit
raise CouldntDecodeError(f"Sample width {self.sample_width} unsupported")
Happy to submit a PR if maintainers agree with the approach.
pydub_wav_dos_pocs.zip
Describe the bug
Expected behavior
pydubshould reject WAV files with unreasonable header values before returning anAudioSegment. Similar to howffmpegitself rejectsdata_size=0xFFFFFFFFwith "invalid start code",pydubshould fail fast onsample_rate > 384000orchannels > 8.Actual behavior
Environment
Impact
Any service accepting user WAV uploads via
pydubis vulnerable to DoS. A 44-byte file can cause:ffmpegattempts to resample 100MHz audioffmpegattempts 64k-channel processingAdditional test cases in zip:
evil_bits.wav:bits_per_sample=65535— loads, fails faster on exportevil_data_size.wav:data_size=0xFFFFFFFF— already rejected byffmpeg, included to show where validation existsSuggested fix
Add bounds checks after parsing fmt chunk in
audio_segment.py:Happy to submit a PR if maintainers agree with the approach.