Skip to content

[Security] Uncontrolled memory allocation in cbor_load() allows DoS via small crafted input #418

@Benjamin608608

Description

@Benjamin608608

Summary

Uncontrolled memory allocation in cbor_load() allows a small crafted CBOR input (as few as 5 bytes) to trigger allocation of gigabytes of memory, causing denial of service.

Vulnerability Details

  • Type: Uncontrolled Resource Consumption (CWE-400)
  • Severity: Medium
  • Location: src/cbor/arrays.c line 105, src/cbor/maps.c (similar), triggered via src/cbor/internal/builder_callbacks.c lines 298 and 324
  • Affected versions: All versions up to and including current master

Description

When cbor_load() processes a definite-length array or map, it pre-allocates memory for all declared elements without any upper bound check. The CBOR format allows declaring up to 2^64 - 1 elements in just 9 bytes of header.

In builder_callbacks.c:

void cbor_builder_array_start_callback(void* context, uint64_t size) {
  CHECK_LENGTH(ctx, size);
  cbor_item_t* res = cbor_new_definite_array(size);  // allocates size * 8 bytes

In arrays.c:

cbor_item_t* cbor_new_definite_array(size_t size) {
  cbor_item_t** data = _cbor_alloc_multiple(sizeof(cbor_item_t*), size);
  // No upper bound on size — allocates size * sizeof(pointer) bytes

CHECK_LENGTH only ensures the value fits in size_t, not that the resulting allocation is reasonable.

Impact

  • 5-byte input \x9a\x11\x27\x00\x00 declares an array of ~287 million elements, attempting to allocate ~2.3 GB
  • 9-byte input can request allocation up to 128 GB (on 64-bit systems)
  • Denial of service for any application parsing untrusted CBOR data via cbor_load()
  • Confirmed via fuzzing: 4 distinct OOM crashes found within seconds

Proof of Concept

OOM-triggering inputs (hex):

9a11270000          — array(0x11270000) = ~287M elements → ~2.3 GB allocation
9abb939390ff        — nested arrays triggering cascading allocations

Suggested Fix

Add a configurable maximum allocation limit, similar to how other parsers handle this:

// Option 1: Add a compile-time limit
#ifndef CBOR_MAX_DEFINITE_ITEMS
#define CBOR_MAX_DEFINITE_ITEMS (1024 * 1024)  // 1M items
#endif

void cbor_builder_array_start_callback(void* context, uint64_t size) {
  CHECK_LENGTH(ctx, size);
  if (size > CBOR_MAX_DEFINITE_ITEMS) {
    ctx->creation_failed = true;
    return;
  }
  // ... proceed with allocation

Or provide a runtime-configurable limit via the decoder context.

Affected Version

Tested on latest master commit. All prior versions likely affected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions