basecamp/fizzy · error · ActionPack::WebAuthn::InvalidCborError

Reserved additional info: #{info}

Error message

Reserved additional info: #{info}

What it means

read_argument decodes the length/argument that follows a CBOR header byte. Additional-info values 28–30 are reserved by RFC 8949 for future standardization and no conformant encoder emits them; encountering one means the header byte is corrupt, so the decoder raises InvalidCborError with the reserved value.

Source

Thrown at lib/action_pack/web_authn/cbor_decoder.rb:235

        Math.ldexp(mantissa, -24)
      elsif exponent == 31
        mantissa == 0 ? Float::INFINITY : Float::NAN
      else
        Math.ldexp(mantissa + 1024, exponent - 25)
      end

      sign == 1 ? -value : value
    end

    def read_argument
      case info = additional_info
      when SIMPLE_VALUE_RANGE then info
      when SINGLE_BYTE_VALUE_FOLLOWS then read_byte
      when TWO_BYTE_VALUE_FOLLOWS then read_bytes(2).pack("C*").unpack1("n")
      when FOUR_BYTE_VALUE_FOLLOWS then read_bytes(4).pack("C*").unpack1("N")
      when EIGHT_BYTE_VALUE_FOLLOWS then read_bytes(8).pack("C*").unpack1("Q>")
      when RESERVED_VALUE_RANGE
        raise ActionPack::WebAuthn::InvalidCborError, "Reserved additional info: #{info}"
      else
        raise ActionPack::WebAuthn::InvalidCborError, "Invalid additional info: #{info}"
      end
    end

    def additional_info(consume: true)
      byte = consume ? read_byte : peek
      byte & 0b00011111
    end

    def indefinite_length?
      read_byte if additional_info(consume: false) == INDEFINITE_LENGTH_MAJOR_TYPE
    end

    def break_code?
      read_byte if peek == BREAK_CODE
    end

View on GitHub (pinned to 7aabe74580)

Solutions

  1. Hex-dump the input and check the failing offset's header byte — low 5 bits in 28..30 confirm corruption.
  2. Re-encode the payload with a standard CBOR library rather than patching bytes.
  3. Rescue ActionPack::WebAuthn::InvalidCborError once at the call site and reject the payload with 400.
  4. Add an integrity check (HMAC or signature verification happens anyway in WebAuthn) before parsing to discard tampered input early.

Example fix

# before
value = ActionPack::WebAuthn::CborDecoder.decode(bytes)

# after — single choke point for every CBOR syntax error (reserved info, bad lengths, truncation)
def decode_cbor(bytes)
  ActionPack::WebAuthn::CborDecoder.decode(bytes)
rescue ActionPack::WebAuthn::InvalidCborError
  raise ApplicationController::BadRequest, 'malformed CBOR payload'
end
Defensive patterns

Strategy: try-catch

Try / catch

begin
  value = ActionPack::WebAuthn::CborDecoder.decode(bytes)
rescue ActionPack::WebAuthn::InvalidCborError => e
  render json: { error: 'malformed CBOR payload' }, status: :bad_request
end

Prevention

When it happens

Trigger: A header byte whose low 5 bits are 28/29/30 (e.g. 0x9C, 0x9D, 0x9E for text strings) anywhere a length argument is read — result of random corruption, fuzzing, or mis-copied byte strings.

Common situations: Bit-rot or transmission errors in binary payloads; hand-assembled CBOR where a length was written as the raw value instead of an encoded argument; concatenating CBOR fragments mid-item.

Related errors


AI-assisted analysis of basecamp/fizzy@7aabe74580 (2026-08-21). Data as JSON: /api/errors/dd55a43f7f30f133. Report an issue: GitHub.