2828 AuthenticatorAssertionResponse ,
2929 AuthenticatorAttestationResponse ,
3030 AuthenticatorSelectionCriteria ,
31+ AuthenticatorTransport ,
3132 PublicKeyCredentialDescriptor ,
3233 RegistrationCredential ,
3334 ResidentKeyRequirement ,
@@ -72,6 +73,15 @@ def _load_challenge(request, key: str) -> bytes:
7273 return base64 .b64decode (encoded )
7374
7475
76+ _VALID_TRANSPORTS = {t .value for t in AuthenticatorTransport }
77+
78+
79+ def _clean_transports (raw ) -> list [str ]:
80+ if not isinstance (raw , list ):
81+ return []
82+ return [t for t in raw if isinstance (t , str ) and t in _VALID_TRANSPORTS ]
83+
84+
7585# ---------------------------------------------------------------------------
7686# Registration — requires an authenticated user
7787# ---------------------------------------------------------------------------
@@ -131,6 +141,7 @@ def passkey_register_complete(request):
131141 except PermissionDenied :
132142 return JsonResponse ({"error" : _ ("No active WebAuthn challenge" )}, status = 400 )
133143
144+ transports = _clean_transports (data .get ("response" , {}).get ("transports" ))
134145 try :
135146 credential = RegistrationCredential (
136147 id = data ["id" ],
@@ -140,7 +151,7 @@ def passkey_register_complete(request):
140151 attestation_object = base64url_to_bytes (
141152 data ["response" ]["attestationObject" ]
142153 ),
143- transports = data [ "response" ]. get ( " transports" , []) ,
154+ transports = transports ,
144155 ),
145156 )
146157 verification = verify_registration_response (
@@ -168,7 +179,7 @@ def passkey_register_complete(request):
168179 credential_id = bytes_to_base64url (verification .credential_id ),
169180 public_key = bytes_to_base64url (verification .credential_public_key ),
170181 sign_count = verification .sign_count ,
171- transports = data [ "response" ]. get ( " transports" , []) ,
182+ transports = transports ,
172183 )
173184 except Exception :
174185 logger .warning (
0 commit comments