Skip to content

bug: ShapeTable.registerWithId race / next_id wraparound enables shape hijack #10

Description

@minagishl

Bug Description

ShapeTable.registerWithId (src/session.zig:124-140) and SessionEncoder.encodeWithSchema (:1521-1527) overwrite or accept inconsistent state under adversarial conditions:

pub fn registerWithId(self: *ShapeTable, allocator: Allocator, shape_id: u64, keys: []const []const u8) !bool {
    if (self.by_id.get(shape_id)) |existing| {
        return eqlNestedBytes(existing.keys, keys);
    }
    if (try self.getId(allocator, keys)) |existing_id| {
        if (existing_id != shape_id) {
            return false;
        }
    }
    try self.insertShape(allocator, shape_id, keys);
    if (self.next_id <= shape_id) {
        self.next_id = shape_id + 1;
    }
    return true;
}

Three issues:

  1. If the attacker can inject a RegisterShape before the legitimate sender's, the attacker's shape becomes canonical. Subsequent ShapedObject(shape_id = X) decodes are read with the attacker's key list.
  2. next_id = shape_id + 1 can be set to u64-near-max by the attacker. Subsequent next_id +%= 1 (wrapping) collisions with previously-registered ids.
  3. The two directions of "same shape, different id" are checked asymmetrically.

Steps to Reproduce

  1. Attacker registers shape id=0 with keys=["admin","role"].
  2. Legit sender later registers shape id=0 with keys=["role","user"]registerWithId returns false (existing matches keys), but legit sender's subsequent ShapedObject(0, [string1, string2]) is decoded with the attacker's keys.

Expected Behavior

  1. Reject registerWithId when the same keys already map to a different id (already partially checked at :131, but the inverse direction should also fail).
  2. Require next_id updates to use std.math.add(u64, ..., 1) and return RecurramError.InvalidData on overflow.
  3. Document and harden the trust model for shape registration (e.g., per-peer namespacing).

Actual Behavior

Race-condition hijack possible; wrap-around possible.

Environment

  • Project: recurram-zig
  • File: src/session.zig:124-140

Additional Context

Severity: High — state corruption attack on cooperating session.

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