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

Invalid additional info: #{info}

Error message

Invalid additional info: #{info}

What it means

read_argument's else-branch fires for additional-info 31 — the indefinite-length/break marker — used where a definite argument is required (for example a positive-integer header 0x1F, or an argument byte of 0xFF leaking into an integer/text context). RFC 8949 allows info 31 only for streaming strings/arrays/maps, so anywhere else it is a protocol violation and InvalidCborError is raised.

Source

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

        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

    def read_bytes(length)
      raise ActionPack::WebAuthn::InvalidCborError, "Unexpected end of input" if @position + length > @bytes.length

View on GitHub (pinned to 7aabe74580)

Solutions

  1. Hex-dump around the failure offset: a header ending in 0x1F or a stray 0xFF in length position confirms misalignment.
  2. Emit the payload from a conformant encoder; do not concatenate partial items.
  3. Validate the byte layout in tests against a golden vector from RFC 8949's appendix.
  4. Rescue InvalidCborError centrally and reject the payload — misaligned CBOR cannot be recovered.

Example fix

# before
combined = indefinite_chunk + definite_chunk # misaligned concatenation
ActionPack::WebAuthn::CborDecoder.decode(combined)

# after — decode each item as its own complete CBOR sequence item
[chunk_a, chunk_b].each { |c| ActionPack::WebAuthn::CborDecoder.decode(c) }
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: Bytes like 0x1F, 0x3F, 0x5F (typed headers with break-info), or a 0xFF break code appearing where the parser expects a length argument — typical when a definite/indefinite concatenation is mixed up or the buffer is misaligned by one byte.

Common situations: Merging a hand-written indefinite-length item with definite-length items; off-by-one slicing that shifts headers; fuzzed payloads; decoders fed the CBOR sequence's second item mid-item of the first.

Related errors


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