basecamp/fizzy · error · ActionPack::WebAuthn::InvalidCborError
Maximum nesting depth exceeded
Error message
Maximum nesting depth exceeded
What it means
The decoder tracks nesting (@depth) and refuses to recurse past MAX_DEPTH (16 by default), raising InvalidCborError. This protects the Ruby VM from stack exhaustion via deeply nested arrays/maps — a classic CBOR compression-bomb shape. Legitimate WebAuthn structures are 3–4 levels deep, so the limit only trips on malformed or hostile input unless you deliberately decode deep custom structures.
Source
Thrown at lib/action_pack/web_authn/cbor_decoder.rb:113
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
when TEXT_STRING_TYPE then decode_text_string
when ARRAY_TYPE then decode_array
when MAP_TYPE then decode_map
when TAG_TYPE then decode_tag
when FLOAT_OR_SIMPLE_TYPE then decode_float_or_simple
end
@depth -= 1
result
end
View on GitHub (pinned to 7aabe74580)
Solutions
- Inspect the payload's nesting before decoding in tests; anything near 16 levels in WebAuthn data is corrupt.
- If your own schema legitimately nests deeper, raise the cap explicitly: CborDecoder.decode(bytes, max_depth: 64).
- Keep the decoder off any unauthenticated endpoint; if exposed, keep default limits and fail closed.
- Rescue InvalidCborError and log bytesize + first bytes to identify the offending producer.
Example fix
# before ActionPack::WebAuthn::CborDecoder.decode(user_supplied_bytes) # after — explicit limits for a trusted, deeply-nested schema ActionPack::WebAuthn::CborDecoder.decode(user_supplied_bytes, max_depth: 64, max_size: 1.megabyte)
Defensive patterns
Strategy: validation
Validate before calling
# for trusted schemas that legitimately nest deeper than 16 ActionPack::WebAuthn::CborDecoder.decode(bytes, max_depth: 64) # for untrusted input, keep the default and pre-check nothing deeper than expected
Type guard
def within_cbor_depth_limit?(bytes, max_depth = ActionPack::WebAuthn::CborDecoder::MAX_DEPTH) # cheap structural check is not possible; rely on decode with explicit limit and rescue ActionPack::WebAuthn::CborDecoder.decode(bytes, max_depth: max_depth) true rescue ActionPack::WebAuthn::InvalidCborError false end
Try / catch
begin
value = ActionPack::WebAuthn::CborDecoder.decode(bytes)
rescue ActionPack::WebAuthn::InvalidCborError => e
# depth bombs and malformed data are both permanent rejections
render json: { error: e.message }, status: :bad_request
end Prevention
- Keep the decoder off unauthenticated endpoints; keep default limits on public ones.
- WebAuthn structures nest 3–4 levels — deeper input is corrupt or hostile.
- Set explicit max_depth matching your schema when you control both ends.
When it happens
Trigger: Decoding CBOR with more than 16 nested arrays/maps, e.g. \x82\x82\x82... repeated; hostile input crafted as a billion-laughs-style nesting bomb; custom non-WebAuthn payloads that embed deep document trees.
Common situations: Exposing CborDecoder on a public endpoint without depth caps; fuzzing runs; migrating from another CBOR gem with no/looser depth limits; legitimate deep structures in domain-specific CBOR.
Related errors
- Input exceeds maximum size
- Unexpected end of input
- Invalid simple value: #{info}
- Reserved additional info: #{info}
- Invalid additional info: #{info}
AI-assisted analysis of basecamp/fizzy@7aabe74580 (2026-08-21).
Data as JSON: /api/errors/e3ec98e6bba67574.
Report an issue: GitHub.