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

Input exceeds maximum size

Error message

Input exceeds maximum size

What it means

CborDecoder caps input at MAX_SIZE (10 megabytes by default) and raises InvalidCborError in initialize when bytes.length exceeds it. Real WebAuthn payloads are a few kilobytes, so hitting this limit almost always means the wrong byte string was passed or the decoder is being used on arbitrary user-supplied data.

Source

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

  MAX_SIZE = 10.megabytes

  # Tags
  POSITIVE_BIGNUM_TAG = 2
  NEGATIVE_BIGNUM_TAG = 3

  class << self
    # Decodes a CBOR-encoded byte sequence into a Ruby object.
    #
    #   ActionPack::WebAuthn::CborDecoder.decode("\xa2\x61a\x01\x61b\x02")
    #   # => {"a" => 1, "b" => 2}
    def decode(bytes, **args)
      bytes = bytes.bytes if bytes.respond_to?(:bytes)
      new(bytes, **args).decode
    end
  end

  def initialize(bytes, max_depth: MAX_DEPTH, max_size: MAX_SIZE) # :nodoc:
    raise ActionPack::WebAuthn::InvalidCborError, "Input exceeds maximum size" if bytes.length > max_size

    @bytes = bytes
    @max_depth = max_depth
    @position = 0
    @depth = 0
  end

  # Decodes the next CBOR data item from the byte sequence.
  def decode
    raise ActionPack::WebAuthn::InvalidCborError, "Unexpected end of input" if @position >= @bytes.length
    raise ActionPack::WebAuthn::InvalidCborError, "Maximum nesting depth exceeded" if @depth >= @max_depth

    @depth += 1

    result = case major_type
    when UNSIGNED_INTEGER_TYPE then decode_unsigned_integer
    when NEGATIVE_INTEGER_TYPE then decode_negative_integer
    when BYTE_STRING_TYPE then decode_byte_string

View on GitHub (pinned to 7aabe74580)

Solutions

  1. Verify what you are decoding: in WebAuthn flows the input should be the attestation object or COSE key slice (bytes-to-kilobytes), never megabytes.
  2. If you legitimately decode large CBOR, raise the ceiling explicitly: CborDecoder.decode(bytes, max_size: 50.megabytes).
  3. Add a bytesize guard at the request boundary and reject oversized payloads with 413 before touching the decoder.
  4. Never pass request.body or file contents straight to the decoder without a size check.

Example fix

# before
CborDecoder.decode(request.body.read)

# after — bound the input explicitly
bytes = request.body.read
return head :payload_too_large if bytes.bytesize > 1.megabyte
CborDecoder.decode(bytes)
Defensive patterns

Strategy: validation

Validate before calling

return head :payload_too_large if bytes.bytesize > ActionPack::WebAuthn::CborDecoder::MAX_SIZE
value = ActionPack::WebAuthn::CborDecoder.decode(bytes)

Type guard

def within_cbor_size_limit?(bytes, limit = ActionPack::WebAuthn::CborDecoder::MAX_SIZE)
  bytes.respond_to?(:bytesize) ? bytes.bytesize <= limit : bytes.length <= limit
end

Try / catch

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

Prevention

When it happens

Trigger: CborDecoder.decode with a payload over 10 MB — e.g. accidentally passing a whole uploaded file or a database blob instead of the attestationObject slice, or feeding the decoder raw request bodies in a generic CBOR endpoint.

Common situations: Custom (non-WebAuthn) use of the decoder on user uploads; a copy-paste bug that passes the full params hash serialized as bytes; denial-of-service probing where attackers pad CBOR input.

Related errors


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