Skip to content

bug: state.shapes.resize(shape_id + 1) with attacker-controlled shape_id (OOM / wraparound) #3

Description

@minagishl

Bug Description

src/v2.rs:443-446 calls state.shapes.resize(shape_id + 1, …) with shape_id taken directly from the wire (a varuint). This produces three failure modes from a single malformed message:

  1. For moderate shape_id values (e.g., 2^30), the resize requests (shape_id + 1) * sizeof(ShapeEntry) bytes and OOMs the process.
  2. For shape_id == u64::MAX, shape_id + 1 wraps in release builds (with overflow-checks disabled) to 0, silently truncating the shape table — a session-state corruption primitive.
  3. In debug builds, the wrap is a checked panic and crashes the process.

Steps to Reproduce

  1. Construct a v2 message that registers a shape with shape_id = 0x7FFF_FFFF_FFFF_FFFF (or any large value).
  2. Call recurram::decode on it.
  3. Observe OOM (large but finite shape_id) or shape-table corruption (u64::MAX).

Expected Behavior

shape_id should be validated against a small configurable cap (e.g., MAX_SHAPES = 65_536) before any resize, or the shape table should be a sparse HashMap keyed by shape_id rather than a dense Vec.

Actual Behavior

state.shapes.resize(shape_id + 1, …) is called with attacker-controlled shape_id.

Environment

  • Crate: recurram, v2 decoder

Additional Context

Severity: Critical — unauthenticated remote OOM / session-state corruption.

// state.shapes.resize(shape_id + 1, ...)

(Replace with exact lines after review.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions