Skip to main content
← All libraries
Codec · C

How to fuzz libopus

Opus blends two codecs in one bitstream — SILK and CELT have separate bug surfaces.

The Opus codec switches between SILK (speech) and CELT (audio) modes and interpolates between them, creating a complex state machine. CELT's band energy quantisation and its range coder must handle every combination of configuration bits — a crash in libopus affects WebRTC, Discord, Zoom, and most real-time communication stacks.

Common bug classes

  • Heap buffer overflow in CELT band energy normalisation
  • Integer overflow in range-coder renormalisation loop
  • Out-of-bounds read in SILK LPC synthesis filter
  • Divide-by-zero in pitch estimator autocorrelation
  • Assertion failure on malformed table-of-contents byte

Recommended setup

Fuzzers

  • AFL++
  • libFuzzer
  • Honggfuzz

Sanitizers

  • ASan
  • UBSan

Harness scaffold

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <opus.h>

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  int err;
  OpusDecoder *dec = opus_decoder_create(48000, 2, &err);
  if (!dec) return 0;
  const int MAX_FRAME = 5760; /* 120 ms at 48 kHz */
  opus_int16 *pcm = malloc(MAX_FRAME * 2 * sizeof(opus_int16));
  if (pcm) {
    opus_decode(dec, data, (opus_int32)size, pcm, MAX_FRAME, 0);
    free(pcm);
  }
  opus_decoder_destroy(dec);
  return 0;
}

Save this as fuzz_target.cc, build with your compiler + sanitizer flags, and you have a working starting point.

Notable CVEs found by fuzzing

  • CVE-2017-0381
Start fuzzing libopus on Fuzze.rs →

Push the harness above + a Dockerfile. First month 50% off.