basecamp/fizzy · error · ActionPack::WebAuthn::InvalidResponseError
Authenticator data is too short for credential ID and public
Error message
Authenticator data is too short for credential ID and public key
What it means
With attested credential data present, the parser reads a 2-byte credential ID length, then requires the remaining buffer to hold at least credential_id_length bytes plus 1 or more bytes of COSE public key (the +1 guarantees a non-empty key). If the declared ID length overruns the buffer or the public key is missing entirely, InvalidResponseError is raised.
Source
Thrown at lib/action_pack/web_authn/authenticator/data.rb:114
aaguid = nil
credential_id = nil
public_key_bytes = nil
if flags & ATTESTED_CREDENTIAL_DATA_FLAG != 0
if bytes.length < position + AAGUID_LENGTH + CREDENTIAL_ID_LENGTH_BYTES
raise ActionPack::WebAuthn::InvalidResponseError, "Authenticator data is too short for attested credential data"
end
aaguid_bytes = bytes[position, AAGUID_LENGTH].pack("C*")
aaguid = aaguid_bytes.unpack("H8H4H4H4H12").join("-")
position += AAGUID_LENGTH
credential_id_length = bytes[position, CREDENTIAL_ID_LENGTH_BYTES].pack("C*").unpack1("n")
position += CREDENTIAL_ID_LENGTH_BYTES
if bytes.length < position + credential_id_length + 1
raise ActionPack::WebAuthn::InvalidResponseError, "Authenticator data is too short for credential ID and public key"
end
credential_id = Base64.urlsafe_encode64(bytes[position, credential_id_length].pack("C*"), padding: false)
position += credential_id_length
public_key_bytes = bytes[position..].pack("C*")
end
new(
bytes: bytes,
relying_party_id_hash: relying_party_id_hash,
flags: flags,
sign_count: sign_count,
aaguid: aaguid,
credential_id: credential_id,
public_key_bytes: public_key_bytes
)
endView on GitHub (pinned to 7aabe74580)
Solutions
- Verify in console: decode the data, check bytesize > 55 + declared credential ID length, and that the trailing bytes form valid CBOR (they decode via CborDecoder.decode).
- Pass through the browser's response.getPublicKey()/attestation object bytes untouched instead of re-encoding.
- Raise or remove request body-size limits that could clip large credential IDs (some are 255+ bytes, security keys even 1023).
- Rescue ActionPack::WebAuthn::InvalidResponseError at the controller boundary and return 400 with a registration-failed message.
Example fix
# before
# reconstructing data field-by-field (breaks byte math)
auth_data = rp_hash + flags + sign_count + aaguid + [id_len].pack('n') + id_bytes # key forgotten
# after — forward the browser's buffer whole
response = ActionPack::WebAuthn::Authenticator::AttestationResponse.new(
client_data_json: params[:client_data_json],
authenticator_data: params[:authenticator_data], # full base64url buffer, untouched
...
) Defensive patterns
Strategy: try-catch
Validate before calling
raw = Base64.urlsafe_decode64(params[:authenticator_data].to_s)
if raw.bytesize > 55 && (raw.getbyte(32) & 0x40) != 0
id_len = raw[53, 2].unpack1('n')
return render(json: { error: 'credential id/key truncated' }, status: :bad_request) if raw.bytesize < 55 + id_len + 1
end Type guard
def plausible_attested_credential?(raw)
return true if (raw.getbyte(32) & 0x40).zero?
id_len = raw[53, 2].unpack1('n')
raw.bytesize >= 55 + id_len + 1
end Try / catch
begin
response.validate!
rescue ActionPack::WebAuthn::InvalidResponseError => e
render json: { error: e.message }, status: :bad_request
end Prevention
- Don't impose request-size caps that clip large credential IDs (up to 1023 bytes).
- Pass COSE key bytes as raw binary; the parser expects CBOR bytes, not hex or JSON.
- Treat any short-buffer error as permanent client corruption — reject, don't retry.
When it happens
Trigger: A registration response where the credential ID length field claims more bytes than remain; a truncated attestation that cut off everything after the credential ID; a client that appends the COSE key as text/JSON instead of raw CBOR bytes so the byte math no longer lines up.
Common situations: Buffers truncated at a fixed request-size limit; custom client-side assembly of authenticatorData from parts; byte-slice off-by-one bugs in bespoke parsers feeding this API; fixtures copied from a different authenticator with a different credential ID size.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Authenticator data is too short for attested credential data
- Authenticator data is too short
- Unexpected end of input
- Invalid base64 encoding in authenticator data
- Client data is not valid JSON
AI-assisted analysis of basecamp/fizzy@7aabe74580 (2026-08-21).
Data as JSON: /api/errors/c5e3d4cc720a2b4f.
Report an issue: GitHub.